前面章节对 Hystrix 进行了简单的介绍,在本章我们将通过一个简单的实例来介绍 Hystrix 的具体用法。本实例的主要步骤如下:
配置 Eureka Server:提供服务注册、服务列表功能;
提供 User 服务:提供一个简单服务,供 Hystrix 实例调用;
Hystrix 实例:简单的 Hystrix 实例;
在使用 Eureka Server 前,我们需要在 pom.xml 添加如下 maven 依赖:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
配置 Eureka Server 注册中心,配置文件内容如下:
# 服务端口 server: port: 8077 # 服务名称 spring: application: name: eureka-server # 服务地址 eureka: instance: hostname: localhost client: # 向注册中心注册自己 register-with-eureka: true # 取消检索服务 fetch-registry: true # 启动独立模式的Eureka server # 关闭客户端行为,这样它就不会不断尝试并无法到达它的对等端 # defaultZone 默认使用 http://localhost:8761/eureka/ 地址 # 使 serviceUrl 指向与本地实例相同的主机 service-url: defaultZone: http://127.0.0.1:8077/eureka/ server: # 开启注册中心的保护机制,默认是开启 enable-self-preservation: true # 设置保护机制的阈值,默认是0.85 renewal-percent-threshold: 0.5
编写 Eureka Server 启动类,需要在启动类上添加 @EnableEurekaServer 注解,完整代码如下:
package com.hxstrive.springcloud.ribbon_eureka_server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class RibbonEurekaServerApplication { public static void main(String[] args) { SpringApplication.run(RibbonEurekaServerApplication.class, args); } }
由于 User 服务需要将服务注册到 Eureka Server 注册中心,因此需要在 pom.xml 中添加 Eureka Clinet 的 maven 依赖。如下:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
在该配置文件中配置 Eureka Server 的注册中心信息,配置如下:
# 服务端口 server: port: 7001 spring: application: name: user # 服务地址 eureka: instance: hostname: localhost # 心跳间隔5s,默认30s。每一个服务配置后,心跳间隔和心跳超时时间会被保存在server端, # 不同服务的心跳频率可能不同,server 端会根据保存的配置来分别探活 lease-renewal-interval-in-seconds: 5 # 心跳超时时间10s,默认90s。从client端最后一次发出心跳后,达到这个时间没有再次发出 # 心跳,表示服务不可用,将它的实例从注册中心移除 lease-expiration-duration-in-seconds: 10 client: service-url: # 注册中心路径,表示我们向这个注册中心注册服务,如果向多个注册中心注册,用“,”进行分隔 defaultZone: http://localhost:8077/eureka appName: server: user1
编写 User 服务的启动类,在该类上添加 @EnableEurekaClient 注解开启 Eureka Client 功能。代码如下:
package com.hxstrive.springcloud.ribbon_service_users; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Date; @RestController @SpringBootApplication @EnableEurekaClient public class RibbonServiceUsersApplication { @Value("${appName:server}") private String appName; public static void main(String[] args) { SpringApplication.run(RibbonServiceUsersApplication.class, args); } @GetMapping("/info") public String getInfo() { try { Thread.sleep((long) (Math.random() * 1000)); } catch (Exception e) { e.printStackTrace(); } return "From " + appName + " - " + new Date(); } }
在 RibbonServiceUsersApplication 类中,仅仅提供了一个 /info 服务。该服务将使用 Thread.sleep() 方法模拟延迟功能,然后返回带有时间的字符串。
在使用 Hystrix 之前,我们需要先添加 maven 依赖。如下:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> <version>2.0.0.RELEASE</version> </dependency>
添加 application.yml 配置文件,在该配置文件中配置注册中心地址。内容如下:
server: port: 8080 spring: application: name: demo # 服务地址 eureka: instance: hostname: localhost # 心跳间隔5s,默认30s。每一个服务配置后,心跳间隔和心跳超时时间会被保存在server端, # 不同服务的心跳频率可能不同,server 端会根据保存的配置来分别探活 lease-renewal-interval-in-seconds: 5 # 心跳超时时间10s,默认90s。从client端最后一次发出心跳后,达到这个时间没有再次发出 # 心跳,表示服务不可用,将它的实例从注册中心移除 lease-expiration-duration-in-seconds: 10 client: service-url: # 注册中心路径,表示我们向这个注册中心注册服务,如果向多个注册中心注册,用“,”进行分隔 defaultZone: http://localhost:8077/eureka
添加 RestTemplate 配置,并且在该 restTemplate() 上面添加 @LoadBalanced 注解。开启负载均衡策略功能,代码如下:
package com.hxstrive.springcloud.hystrix; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; /** * RestTemplate 配置 * @author Administrator 2021/3/11 13:35 */ @Configuration public class RestTemplateConfig { // 配置一个 RestTemplate @Bean // 添加该注解后,可以使得 RestTemplate 拥有负载均衡能力 @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
使用 RestTemplate 调用上面提供的 User 服务,代码如下:
package com.hxstrive.springcloud.hystrix; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; @Component public class DemoService { @Autowired private RestTemplate restTemplate; public String getInfo() { System.out.println("restTemplate=" + restTemplate); // 如果你要实现负载均衡,调用地址不能写具体主机地址 // 需要将主机地址替换成对于服务的服务名,即 spring.application.name 指定的值 // 你也可以到 Eureka server 中去查看 String url = "http://USER/info"; ResponseEntity<String> resp = restTemplate.getForEntity(url, String.class); if(resp.getStatusCode().is2xxSuccessful()) { return resp.getStatusCode().value() + " :: " + resp.getBody(); } else { return resp.getStatusCode().value() + " :: " + resp.getBody(); } } }
实例代码,使用 @EnableCircuitBreaker 开启断路器功能。并且,在 index() 和 demo() 方法上面使用 @HystrixCommand 注解标记该方法启用 Hystrix 功能。通过 @HystrixCommand 注解的 fallbackMethod 属性指定当服务不可用时回调方法。代码如下:
package com.hxstrive.springcloud.hystrix; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @SpringBootApplication // 启用断路器 @EnableCircuitBreaker public class HystrixDemo1Application { @Autowired private DemoService demoService; public static void main(String[] args) { SpringApplication.run(HystrixDemo1Application.class, args); } @GetMapping({"/"}) @HystrixCommand(fallbackMethod = "fallback") public String index() { return demoService.getInfo(); } /** * 当服务调用失败时,调用此方法 * @return */ private String fallback() { return "很抱歉,网络拥挤!"; } @GetMapping({"/demo"}) @HystrixCommand(fallbackMethod = "fallback2") public String demo(String name) { return "name=" + name + ", " + demoService.getInfo(); } /** * 当服务调用失败时,调用此方法 * @return */ private String fallback2(String name) { return "很抱歉,网络拥挤!name=" + name; } }
熔断器的回调方法参数列表需要和主方法保持一致。例如:demo(String name) 和 fallback2(String name) 方法。
第一步:启动 Eureka Server 服务;
第二步:启动 User 服务,然后通过浏览器查看 User 服务是否已经注册到 Eureka Server 中;
第三步:启动 Hystrix 实例,通过浏览器访问实例,访问正常。如果我们将 User 服务暂停,再次访问 Hystrix 实例,返回信息为回退方法返回的值。