和 Ribbon 等组件一样, 在项目中, Hystrix 一般不会单独出现, 而是会和 Eureka 等组件配套出现. 在 Hystrix 和 Eureka 整合后的框架里, 一般会用到 Hystrix 的断路器以及合并请求等特性, 而在 web 框架里, 大多会有专门的缓存组件, 所以不怎么会用到 Hystrix 的缓存特性.
1 准备 Eureka 服务器项目
HystrixEurekaServer 项目承担着 Eureka 服务器的作用, 这部分的代码关键点如下.
第一, 在 pom.xml 里, 通过如下关键代码引入 Eureka 服务器组件的依赖包.
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka-server</artifactId>
- </dependency>
第二, 在 application.YAML 里, 指定了本项目的主机名和端口号, 并指定了对外提供 eureka 服务的 Url 路径, 代码如下.
- server:
- port: 8888
- eureka:
- instance:
- hostname: localhost
- client:
- register-with-eureka: false
- fetch-registry: false
- serviceUrl:
- defaultZone: http://localhost:8888/eureka/
第三, 在 ServerStarter.java 里, 编写启动 Eureka 服务的代码, 这里请注意, 在第 2 和第 3 行里, 通过注解声明了本类是 Eureka 服务器的启动类.
- // 省略必要的 package 和 import 的代码
- @EnableEurekaServer
- @SpringBootApplication
- public class ServerStarter
- {
- public static void main( String[] args )
- { SpringApplication.run(ServerStarter.class, args); }
- }
2 服务提供者的代码结构
HystrixEurekaserviceProvider 项目承担着 Eureka 服务提供者的角色. 在 pom.xml 里, 我们除了指定 Eureka 的依赖包以外, 还了指定了 Hystrix 的依赖包, 关键代码如下. 其中, 前 4 行指定的是 Eureka 的依赖包, 后 4 行指定的是 Hystrix 的依赖包.
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-eureka</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-hystrix</artifactId>
- </dependency>
而在 application.YAML 里, 指定了本项目的服务端口是 1111, 对外提供的项目名是 hystrixEureka, 以及是向第一部分指定的 Eureka 服务器注册, 代码如下.
- server:
- port: 1111
- spring:
- application:
- name: hystrixEureka
- eureka:
- client:
- serviceUrl:
- defaultZone: http://localhost:8888/eureka/
3 在服务提供者项目里引入断路器机制
在服务提供者的启动类 ServiceProviderApp.java 里, 我们是通过加入 @EnableCircuitBreaker 注解来启动断路器, 代码如下.
- // 省略必要的 package 和 import 代码
- @SpringBootApplication
- @EnableEurekaClient
- @EnableCircuitBreaker
- @ServletComponentScan
- public class ServiceProviderApp
- {
- public static void main( String[] args )
- { SpringApplication.run(ServiceProviderApp.class, args); }
- }
在 Controller.java 这个控制器类里, 我们是在第 9 行里, 通过调用 service 类提供的方法来返回具体的 OrderDetail 信息, 代码如下.
- // 省略必要的 package 和 import 代码
- @RestController
- public class Controller {
- @Autowired
- private OrderDetailService service;
- // 对外提供服务的 getOrderDetailById 方法
- @RequestMapping(value = "/getOrderDetailById/{orderId}", method = RequestMethod.GET)
- public OrderDetail getOrderDetailById(@PathVariable("orderId") String orderId) throws Exception {
- return service.getOrderDetailByID(orderId);
- }
- }
在 OrderDetailService.java 里, 我们用 HashMap 这个数据结构来模拟数据库, 以此来模拟从数据库读 OrderDetail 的方式, 提供了 "根据 ID 找相应对象的服务", 代码如下.
- // 省略必要的 package 和 import 代码
- @Service
- public class OrderDetailService {
- static HashMap<String,String> orderDB = new HashMap<String,String> ();
- static // 通过 static 代码, 模拟数据库中存储的 OrderDetail 信息
- {
- orderDB.put("1","Peter");
- orderDB.put("2","Tom");
- orderDB.put("3","Mike");
- }
- // 在方法之前, 通过注解引入 Hystrix, 并指定回退方法
- @HystrixCommand(fallbackMethod = "getFallback")
- public OrderDetail getOrderDetailByID(String id) throws Exception
- {
- OrderDetail orderDetail = new OrderDetail();
- if("error".equals(id) ) // 如果输入是 error, 则故意抛出异常
- {throw new Exception(); }
- // 模拟地从数据库里得到信息并返回
- orderDetail.setOrderId(id);
- orderDetail.setOrderOwner(orderDB.get(id));
- return orderDetail;
- }
- // 定义 Hystrix 的回退方法
- public OrderDetail getFallback(String orderId) {
- OrderDetail orderDetail = new OrderDetail();
- orderDetail.setOrderId("error");
- orderDetail.setOrderOwner("error");
- System.out.println("In fallbackForOrderDetail function");
- return orderDetail;
- }
- }
在第 13 行的 getOrderDetailByID 方法之前, 我们在第 12 行通过 fallbackMethod 定义了回退方法, 在这个方法的第 16 行里, 我们定义了如果输入是 error, 那么则将抛出异常, 以此触发回退方法 getFallback. 而在第 24 行定义的回退方法里, 我们将返回一个 ID 和 Owner 都是 error 的 OrderDetail 对象. 本类用到的 OrderDetail 模型类定义如下.
- public class OrderDetail{
- private String orderId;// 订单 id
- private String orderOwner; // 订单所有人
- // 省略必要的 get 和 set 方法
- }
至此我们完成了开发工作, 启动 HystrixEurekaServer 和 HystrixEurekaserviceProvider 后, 如果在浏览器中输入 http://localhost:1111/getOrderDetailById/1 , 能看到如下的输出, 这说明走的是正常的流程.
{"orderId":"1","orderOwner":"Peter"}
但如果输入的是 http://localhost:1111/getOrderDetailById/error , 那么会在 OrderDetailService 类的 getOrderDetailByID 方法里抛出异常, 从而走 Hystrix 的回退流程, 由此会输入如下的语句.
{"orderId":"error","orderOwner":"error"}
在这个案例中, 我们是在 "提供者服务" 的模块引入 hytrix 断路器, 而不是在 "服务调用" 模块, 这和项目中的常规做法相符, 因为启动断路器的场景一般是 "提供服务模块的流量超载".
来源: https://www.cnblogs.com/JavaArchitect/p/9874631.html