Spring cloud系列十一 @Feign集成的Hystrix进行个性化配置及集成原理

1. 概述

上文Spring cloud系列十 使用@HystrixCommand使用Hystrix组件及@EnableCircuitBreaker原理介绍介绍了Hystrix的基本用法。我们已知Spring Cloud的@Feign已经集成了Hystrix的功能。本文我们介绍如何内容:

  • 在Spring Cloud中,在Feign中开启Hystrix功能
  • 为集成在Feign中的Hystrix进行个性化配置。
  • Feign集成Hystrix的原理介绍

2. 相关的工程说明

  • 1 cloud-registration-center:注册中心
  • 2 cloud-service-hystrix: 作为服务方的工程
  • 3 cloud-consumer-hystrix:通过Fegin+Hystrix调用cloud-service-hystrix的接口

本节使用的工程和Spring cloud系列十 使用@HystrixCommand使用Hystrix组件及@EnableCircuitBreaker原理介绍相同
其中cloud-registration-center和cloud-service-hystrix完全相同,请参考这篇文章

3. cloud-consumer-hystrix

功能:此工程实现在Feign中开启Hystrix功能

3.1 pom.xml

关键jar


<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-feignartifactId>
dependency>

<dependency>
    <groupId>org.springframework.cloudgroupId>
    <artifactId>spring-cloud-starter-hystrixartifactId>
dependency>

3.2. 配置属性文件

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

3.3. IMyHystrixClient和MyHystrixClientFallbackFactory

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());
    }

}

3.4. 为集成在Feign中的Hystrix进行个性化配置

以下配置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
……

3.5. 启动类:HystrixFeignCloudConsumerApplication

@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);
    }
}

4. 测试

测试服务

  • 1 启动工程cloud-registration-center:
    配置中心地址:http://127.0.0.1:10761
  • 2 启动工程cloud-service-hystrix的HystrixCloudServiceApplication的启动类
  • 3 启动工程cloud-consumer-hystrix的HystrixFeignCloudConsumerApplication 的启动类

测试一:

执行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已经被关闭了,说明我们的配置启作用了

5. Feign集成Hystrix人原理简单介绍

5.1. @FeignClient

@FeignClient有个方法defaultConfiguration设置客户端Feigin的配置信息,默认情况下此值为空,此时会默认使用FeignClientsConfiguration

// 默认值: 如果此值为空,则默认使用FeignClientsConfiguration
Class[] defaultConfiguration() default {}; 

5.2. FeignClientsConfiguration

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);
}

…
}

5.3. HystrixFeign

HystrixFeign: 使用hystrix断路器装饰Feign的方法,允许Feign接口返回HystrixCommand 或 rx.Observable 或 rx.Single objects,达到在Feign使用hystrix的目的

5.4. FeignContext

创建feign客户端实例的工厂类,为每个feign客户端创建Spring上下文,并注入上文提到的Fegin的默认配置参数FeignClientsConfiguration

public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
     

    public FeignContext() {
        super(FeignClientsConfiguration.class, "feign", "feign.client.name");
    }

}

5.5. FeignAutoConfiguration

方法feignContext(): 会创建类FeignContext

@Configuration
@ConditionalOnClass(Feign.class)
public class FeignAutoConfiguration {
     

    @Bean
    public FeignContext feignContext() {
        FeignContext context = new FeignContext();
        context.setConfigurations(this.configurations);
        return context;
    }
...
}

5.6. spring.factories

通过此配置将FeignAutoConfiguration注册到自动配置中

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
…
org.springframework.cloud.netflix.feign.FeignAutoConfiguration,\
….

通过以上的信息,我们生成了Feign客户端时所需要的Feign ApplicationContext,默认信息是以FeignClientsConfiguration为基础

5.7 @EnableFeignClients

注解在启动类上,扫描启动类所在包和子包中所有的被@FeignClient注解的类,并把将其注册为BeanDefinition到ApplicationContext中。
当我们创建Feign客户端时,会根据以上所有的feign的组件生成我们真正的调用Feign的代理类

6. 代码

以上的详细的代码见下面
github代码,请尽量使用tag v0.8,不要使用master,因为我不能保证master代码一直不变

你可能感兴趣的:(spring-cloud,Spring,Cloud使用总结,spring-cloud,hystrix,feign)