一、官网文档阅读
二、示例
添加hystrix依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
修改movie服务的controller
1 package com.zwjk.cloud.controller; 2 3 import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; 4 import com.zwjk.cloud.entity.User; 5 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.beans.factory.annotation.Value; 7 import org.springframework.cloud.client.ServiceInstance; 8 import org.springframework.cloud.client.loadbalancer.LoadBalancerClient; 9 import org.springframework.web.bind.annotation.GetMapping; 10 import org.springframework.web.bind.annotation.PathVariable; 11 import org.springframework.web.bind.annotation.RestController; 12 import org.springframework.web.client.RestTemplate; 13 14 /** 15 * @author : Jixiaohu 16 * @Date : 2019-04-11. 17 * @Time : 9:38. 18 * @Description : 19 */ 20 @RestController 21 public class MovieController { 22 23 @Autowired 24 private RestTemplate restTemplate; 25 26 @Value("${user.userServicePath}") 27 private String userServicePath; 28 29 @GetMapping("/movie/{id}") 30 @HystrixCommand(fallbackMethod = "findByIdFallback") 31 public User findById(@PathVariable Long id) { 32 return this.restTemplate.getForObject(this.userServicePath + id, User.class); 33 } 34 35 36 public User findByIdFallback(Long id) { 37 User user = new User(); 38 user.setId(0L); 39 user.setName("失败"); 40 return user; 41 } 42 }
这边需要注意的是,fallbackMethod方法的返回值和入参,必须和原方法一致,下面进行测试:
可以看到,这里返回了正常的结果,下面停掉user服务
可以看到,这里返回的结果,就是fallbackMethod里面返回的内容,hystrix就起了作用。
下面,继续看一下
Feign Hystrix Support
参考官网使用示例:
1 @FeignClient(name = "hello", fallback = HystrixClientFallback.class) 2 protected interface HystrixClient { 3 @RequestMapping(method = RequestMethod.GET, value = "/hello") 4 Hello iFailSometimes(); 5 } 6 7 static class HystrixClientFallback implements HystrixClient { 8 @Override 9 public Hello iFailSometimes() { 10 return new Hello("fallback"); 11 } 12 }
在配置文件中,增加开启feign使用断路器
feign: hystrix: enabled: true
按照示例,我们在movie服务中,新增UserFeignClientFallback类
1 package com.zwjk.cloud.fegin; 2 3 import com.zwjk.cloud.entity.User; 4 import org.springframework.stereotype.Component; 5 6 /** 7 * @author : Jixiaohu 8 * @Date : 2019-04-17. 9 * @Time : 18:20. 10 * @Description : 11 */ 12 @Component 13 public class UserFeignClientFallback implements UserFeignClient { 14 @Override 15 public User findById(Long id) { 16 User user = new User(); 17 user.setId(0L); 18 return user; 19 } 20 }
在fegin上增加相应的注解:
1 package com.zwjk.cloud.fegin; 2 3 import com.zwjk.cloud.entity.User; 4 import org.springframework.cloud.openfeign.FeignClient; 5 import org.springframework.web.bind.annotation.GetMapping; 6 import org.springframework.web.bind.annotation.PathVariable; 7 import org.springframework.web.bind.annotation.PostMapping; 8 import org.springframework.web.bind.annotation.RequestBody; 9 10 /** 11 * @author : Jixiaohu 12 * @Date : 2019-04-12. 13 * @Time : 16:50. 14 * @Description : 15 */ 16 @FeignClient(name = "microservice-provider-user", fallback = UserFeignClientFallback.class) 17 public interface UserFeignClient { 18 //@PathVariable得设置value 19 @GetMapping("/simple/{id}") 20 User findById(@PathVariable("id") Long id); //@PathVariable得设置value 21 }
启动项目,进行测试,
同样的,停掉user服务,再次访问这个地址:
就可以实现熔断服务
当一个项目中,有个feign时,如何禁用一些feign的hystrix?
查看一下官网文档
通过配置加上feignBuilder,就可以禁用指定fegin的hystrix
查看一下代码实现:
1 package com.zwjk.cloud.controller; 2 3 import com.zwjk.cloud.entity.User; 4 import com.zwjk.cloud.fegin.UserFeignClient2; 5 import com.zwjk.cloud.fegin.UserFeignClient; 6 import org.springframework.beans.factory.annotation.Autowired; 7 import org.springframework.web.bind.annotation.GetMapping; 8 import org.springframework.web.bind.annotation.PathVariable; 9 import org.springframework.web.bind.annotation.RestController; 10 11 /** 12 * @author : Jixiaohu 13 * @Date : 2019-04-11. 14 * @Time : 9:38. 15 * @Description : 16 */ 17 @RestController 18 public class MovieController { 19 20 @Autowired 21 private UserFeignClient userFeignClient; 22 23 @Autowired 24 private UserFeignClient2 userFeignClient2; 25 26 @GetMapping("/movie/{id}") 27 public User findById(@PathVariable Long id) { 28 return this.userFeignClient.findById(id); 29 } 30 31 @GetMapping("/{serviceName}") 32 public String findServiceInfoFromEurekaByServiceName(@PathVariable String serviceName) { 33 return this.userFeignClient2.findServiceInfoFromEurekaByServiceName(serviceName); 34 } 35 36 37 }
两个fegin:
1 package com.zwjk.cloud.fegin; 2 3 import com.zwjk.cloud.entity.User; 4 import com.zwjk.config.UserConfiguration; 5 import feign.Param; 6 import feign.RequestLine; 7 import org.springframework.cloud.openfeign.FeignClient; 8 9 /** 10 * @author : Jixiaohu 11 * @Date : 2019-04-12. 12 * @Time : 16:50. 13 * @Description : 14 */ 15 @FeignClient(name = "microservice-provider-user", configuration = UserConfiguration.class, fallback = 16 UserFeignClientFallback.class) 17 public interface UserFeignClient { 18 //@PathVariable得设置value 19 @RequestLine("GET /simple/{id}") 20 User findById(@Param("id") Long id); //@PathVariable得设置value 21 22 }
1 package com.zwjk.cloud.fegin; 2 3 import com.zwjk.config.UserConfiguration2; 4 import org.springframework.cloud.openfeign.FeignClient; 5 import org.springframework.web.bind.annotation.PathVariable; 6 import org.springframework.web.bind.annotation.RequestMapping; 7 8 /** 9 * @author : Jixiaohu 10 * @Date : 2019-04-13. 11 * @Time : 11:23. 12 * @Description : 13 */ 14 @FeignClient(name = "xxxx", url = "http://192.168.1.114:8761/", configuration = UserConfiguration2.class) 15 public interface UserFeignClient2 { 16 @RequestMapping(value = "/eureka/apps/{serviceName}") 17 public String findServiceInfoFromEurekaByServiceName(@PathVariable("serviceName") String serviceName); 18 }
两个fallback
1 package com.zwjk.cloud.fegin; 2 3 import org.springframework.stereotype.Component; 4 5 /** 6 * @author : Jixiaohu 7 * @Date : 2019-04-17. 8 * @Time : 18:20. 9 * @Description : 10 */ 11 @Component 12 public class UserFeignClient2Fallback implements UserFeignClient2 { 13 14 @Override 15 public String findServiceInfoFromEurekaByServiceName(String serviceName) { 16 return "hahahha"; 17 } 18 }
1 package com.zwjk.cloud.fegin; 2 3 import com.zwjk.cloud.entity.User; 4 import org.springframework.stereotype.Component; 5 6 /** 7 * @author : Jixiaohu 8 * @Date : 2019-04-17. 9 * @Time : 18:20. 10 * @Description : 11 */ 12 @Component 13 public class UserFeignClientFallback implements UserFeignClient { 14 @Override 15 public User findById(Long id) { 16 User user = new User(); 17 user.setId(0L); 18 return user; 19 } 20 }
看一下两个配置文件
1 package com.zwjk.config; 2 3 import feign.Contract; 4 import feign.Logger; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 8 /** 9 * @author : Jixiaohu 10 * @Date : 2019-04-13. 11 * @Time : 10:20. 12 * @Description : 13 */ 14 @Configuration 15 public class UserConfiguration { 16 17 @Bean 18 public Contract feignContract() { 19 return new feign.Contract.Default(); 20 } 21 22 @Bean 23 Logger.Level feignLoggerLevel() { 24 return Logger.Level.FULL; 25 } 26 }
1 package com.zwjk.config; 2 3 import feign.Feign; 4 import feign.auth.BasicAuthRequestInterceptor; 5 import org.springframework.context.annotation.Bean; 6 import org.springframework.context.annotation.Configuration; 7 import org.springframework.context.annotation.Scope; 8 9 /** 10 * @author : Jixiaohu 11 * @Date : 2019-04-13. 12 * @Time : 11:25. 13 * @Description : 14 */ 15 @Configuration 16 public class UserConfiguration2 { 17 @Bean 18 public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { 19 return new BasicAuthRequestInterceptor("user", "password123"); 20 } 21 22 @Configuration 23 public class FooConfiguration { 24 @Bean 25 @Scope("prototype") 26 public Feign.Builder feignBuilder() { 27 return Feign.builder(); 28 } 29 } 30 }
启动服务,进行测试
下面,我们停掉eureka,和user服务,在一次查看返回结果
启用hystrix的返回结果如下:
没有启用hystrix的返回结果,提示500错误
从中,可以看出,hytrix的熔断,可以有很细的粒度。
如果想要查看fallback回退的原因,可以使用可以使用@FeignClient中的fallbackFactory属性。
看一下如何实现?
参考一下官网文档:
先写一个hystrixFactory:
1 package com.zwjk.cloud.fegin; 2 3 import com.zwjk.cloud.entity.User; 4 import feign.hystrix.FallbackFactory; 5 import org.slf4j.Logger; 6 import org.slf4j.LoggerFactory; 7 import org.springframework.stereotype.Component; 8 9 /** 10 * @author : Jixiaohu 11 * @Date : 2019-04-17. 12 * @Time : 19:37. 13 * @Description : 14 */ 15 @Component 16 public class UserFeginClientFactory implements FallbackFactory<UserFeignClient> { 17 18 private static final Logger Log = LoggerFactory.getLogger(UserFeginClientFactory.class); 19 20 @Override 21 public UserFeignClient create(Throwable cause) { 22 UserFeginClientFactory.Log.info("fallback:reason was : {}", cause.getMessage()); 23 return id -> { 24 User user = new User(); 25 user.setId(-1L); 26 user.setName("haha"); 27 return user; 28 }; 29 } 30 }
修改一下原feignClient
1 package com.zwjk.cloud.fegin; 2 3 import com.zwjk.cloud.entity.User; 4 import org.springframework.cloud.openfeign.FeignClient; 5 import org.springframework.web.bind.annotation.GetMapping; 6 import org.springframework.web.bind.annotation.PathVariable; 7 import org.springframework.web.bind.annotation.PostMapping; 8 import org.springframework.web.bind.annotation.RequestBody; 9 10 /** 11 * @author : Jixiaohu 12 * @Date : 2019-04-12. 13 * @Time : 16:50. 14 * @Description : 15 */ 16 @FeignClient(name = "microservice-provider-user", fallbackFactory = 17 UserFeginClientFactory.class) 18 public interface UserFeignClient { 19 //@PathVariable得设置value 20 @GetMapping("/simple/{id}") 21 User findById(@PathVariable("id") Long id); //@PathVariable得设置value 22 }
启动user服务,movie服务,先正常访问:
然后关闭user服务,会发现控制台开始打印日志:
这是为什么呢?因为此时,断路器并没有打开,实际的原因是TimeoutException
当断路器打开时,就会答应异常的信息。