上文Spring cloud系列十 使用@HystrixCommand使用Hystrix组件及@EnableCircuitBreaker原理介绍介绍了Hystrix的基本用法。我们已知Spring Cloud的@Feign已经集成了Hystrix的功能。本文我们介绍如何内容:
本节使用的工程和Spring cloud系列十 使用@HystrixCommand使用Hystrix组件及@EnableCircuitBreaker原理介绍相同
其中cloud-registration-center和cloud-service-hystrix完全相同,请参考这篇文章
功能:此工程实现在Feign中开启Hystrix功能
关键jar
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-feignartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-hystrixartifactId>
dependency>
bootstrap-hystrix-feign.yml
# port
server:
port: 12082
spring:
application:
# 本服务注册到注册到服务器的名称, 这个名称就是后面调用服务时的服务标识符
name: cloud-consumer-hystrix
eureka:
client:
serviceUrl:
# 服务器注册/获取服务器的zone
defaultZone: http://127.0.0.1:10761/eureka/
instance:
prefer-ip-address: true
application-Hystrix-feign.yml
默认情况下,feign是不启动hystrix功能,需要我们启动此功能
# feign配置
feign:
hystrix:
# 在feign中开启hystrix功能,默认情况下feign不开启hystrix功能
enabled: true
IMyHystrixClient
通过@FeignClient定义Fegin方法,并定义name和fallbackFactory。name属性可用于定义Feign方法的Hystrix的个性化配置,而不使用全局默认配置。fallbackFactory设置带有异常信息的回调方法
@FeignClient(name="cloud-hystrix-service"
, fallbackFactory = MyHystrixClientFallbackFactory.class )
public interface IMyHystrixClient {
@RequestMapping(value = "/hystrix/simple", method = RequestMethod.POST, consumes="application/json; charset=UTF-8")
String simpleHystrixClientCall(@RequestParam("time") long time);
}
MyHystrixClientFallbackFactory
定义回调方法
@Component
public class MyHystrixClientFallbackFactory implements FallbackFactory<IMyHystrixClient> {
private static final Logger log = LoggerFactory.getLogger(MyHystrixClientFallbackFactory.class);
@Override
public IMyHystrixClient create(Throwable throwable) {
return new IMyHystrixClient() {
@Override
public String simpleHystrixClientCall(long time) {
log.error("异常处理={}", throwable);
return "Execute raw fallback: access service fail , req= " + time + " reason = " + throwable;
}
};
}
}
SimpleCtl
control层,定义访问URL接口
@RestController
public class SimpleCtl {
@Autowired
private IMyHystrixClient myHystrixClient;
@RequestMapping(value="/hystrix-feign/simple")
public String simpleClientCall(){
return "rsp: " + myHystrixClient.simpleHystrixClientCall(System.currentTimeMillis());
}
}
以下配置hystrix的线程池的大小、是否开启回退方法。其他的属性配置见Spring cloud系列九 Hystrix的配置属性优先级和详解。这个例子里的配置为所有hystrix配置默认属性,如果需要为特定的Feign方法配置Hystrix配置个性化参数,只需要修改为default为客户端名称即可(这里值和@Feign中name相同)
application-hystrix-feign.yml
# 配置hystrix的参数
hystrix:
threadpool:
# default: 默认参数,作用的所有的hystrix的客户端
default:
coreSize: 10
command:
default:
fallback:
# 是否关闭回退方法
enabled: true
……
@EnableFeignClients:启动Feign
@SpringBootApplication
@EnableFeignClients
@EnableEurekaClient // 配置本应用将使用服务注册和服务发现
public class HystrixFeignCloudConsumerApplication {
public static void main(String[] args) {
args = new String[1];
args[0] = "--spring.profiles.active=hystrix-feign";
SpringApplication.run(HystrixFeignCloudConsumerApplication.class, args);
}
/**
* 使用fastjson做为json的解析器
* @return
*/
@Bean
public HttpMessageConverters fastJsonHttpMessageConverters() {
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fastConverter.setFastJsonConfig(fastJsonConfig);
HttpMessageConverter> converter = fastConverter;
return new HttpMessageConverters(converter);
}
}
测试服务
测试一:
执行cloud-consumer-hystrix的调用cloud-service-hystrix服务的接口
http://127.0.0.1:12082//hystrix-feign/simple
返回:
"rsp: \"time 1511015252093 hystrix1: 434\""
说明fegin方法的调用成功了
测试二:
停止cloud-service-hystrix服务
执行cloud-consumer-hystrix的调用cloud-service-hystrix服务的接口
http://127.0.0.1:12082//hystrix-feign/simple
返回:
"rsp: Execute raw fallback: access service fail , req= 1511186286664 reason = com.netflix.hystrix.exception.HystrixTimeoutException"
说明fallback方法被执行了
测试三:
修改application-hystrix-simple.yml :关闭Hystrix的回退方法
# 配置hystrix的参数
hystrix:
command:
default:
fallback:
# 是否开启回退方法
enabled: false
重启cloud-service-hystrix和cloud-consumer-hystrix,
执行http://127.0.0.1:12082//hystrix-feign/simple
返回
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon Nov 20 21:59:06 CST 2017
There was an unexpected error (type=Internal Server Error, status=500).
IMyHystrixClient#simpleHystrixClientCall(long) timed-out and fallback disabled.
提示方法说fallback已经被关闭了,说明我们的配置启作用了
@FeignClient有个方法defaultConfiguration设置客户端Feigin的配置信息,默认情况下此值为空,此时会默认使用FeignClientsConfiguration
// 默认值: 如果此值为空,则默认使用FeignClientsConfiguration
Class>[] defaultConfiguration() default {};
FeignClientsConfiguration此类会初始化Fegin需要的Encoder 、Decoder 等Bean。其中方法Feign.Builder feignHystrixBuilder() :如果我们配置feign.hystrix.enabled=true会生成封装hystrix的功能的Fegin的代理类
@Configuration
public class FeignClientsConfiguration {
@Configuration
@ConditionalOnClass({ HystrixCommand.class, HystrixFeign.class })
protected static class HystrixFeignConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
// 如果我们配置feign.hystrix.enabled=true会生成封装hystrix的功能的Fegin的代理类
@ConditionalOnProperty(name = "feign.hystrix.enabled", matchIfMissing = false)
public Feign.Builder feignHystrixBuilder() {
return HystrixFeign.builder();
}
}
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() {
return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters));
}
@Bean
@ConditionalOnMissingBean
public Encoder feignEncoder() {
return new SpringEncoder(this.messageConverters);
}
@Bean
@ConditionalOnMissingBean
public Contract feignContract(ConversionService feignConversionService) {
return new SpringMvcContract(this.parameterProcessors, feignConversionService);
}
…
}
HystrixFeign: 使用hystrix断路器装饰Feign的方法,允许Feign接口返回HystrixCommand 或 rx.Observable 或 rx.Single objects,达到在Feign使用hystrix的目的
创建feign客户端实例的工厂类,为每个feign客户端创建Spring上下文,并注入上文提到的Fegin的默认配置参数FeignClientsConfiguration
public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
public FeignContext() {
super(FeignClientsConfiguration.class, "feign", "feign.client.name");
}
}
方法feignContext(): 会创建类FeignContext
@Configuration
@ConditionalOnClass(Feign.class)
public class FeignAutoConfiguration {
@Bean
public FeignContext feignContext() {
FeignContext context = new FeignContext();
context.setConfigurations(this.configurations);
return context;
}
...
}
通过此配置将FeignAutoConfiguration注册到自动配置中
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
…
org.springframework.cloud.netflix.feign.FeignAutoConfiguration,\
….
通过以上的信息,我们生成了Feign客户端时所需要的Feign ApplicationContext,默认信息是以FeignClientsConfiguration为基础
注解在启动类上,扫描启动类所在包和子包中所有的被@FeignClient注解的类,并把将其注册为BeanDefinition到ApplicationContext中。
当我们创建Feign客户端时,会根据以上所有的feign的组件生成我们真正的调用Feign的代理类
以上的详细的代码见下面
github代码,请尽量使用tag v0.8,不要使用master,因为我不能保证master代码一直不变