openfeign 记录

本文基于 JDK8 和 SpringBoot 2.1.5.RELEASE,SpringCloud Greenwich.SR1

一般我们使用 openfeign 都使用 spring-cloud 来引入,使用起来也很简单。这里主要记录下它是如何引入和一些注意的地方。

1. Feign 是如何被引入 Sping 并发挥作用的

首先对于只有接口的调用我们肯定想到动态代理,没错 openfeign 使用的就是 Jdk 动态代理。

引入:

  1. 加入依赖:

    org.springframework.cloud
    spring-cloud-starter-openfeign

  1. 加入注解 @EnableFeignClients,同时
    可以指定扫描包,也可以指定特定的 FeignClient。

到这里引入就结束了,是不是很简单,那如果使用呢?别急,下面会讲到。

1. 自动配置

涉及无负载的自动配置类:FeignAutoConfiguration,FeignClientsConfiguration。
涉及负载均衡的自动配置类:FeignRibbonClientAutoConfiguration,HttpClientFeignLoadBalancedConfiguration,HttpClientFeignLoadBalancedConfiguration,OkHttpFeignLoadBalancedConfiguration

2. 具体的分析

当引入 @EnableFeignClients SpringBoot 会自动引入 @Import(FeignClientsRegistrar.class),那我们来看下 FeignClientsRegistrar。它 实现了 ImportBeanDefinitionRegistrar 类。

FeignClientsRegistrar 如何被引入?
FeignClientsRegistrar 在 Spring 启动时 AbstractApplicationContext#refresh 方法的 invokeBeanFactoryPostProcessors(beanFactory); 这一步被 ConfigurationClassPostProcessor 引入并在 ConfigurationClassBeanDefinitionReader 中调用。

ConfigurationClassPostProcessor 何时被引入
在 SpringApplication#run(String... args) -> createApplicationContext() ->AnnotationConfigApplicationContext 构造方法 -> AnnotatedBeanDefinitionReader 构造方法引入

我们继续看 FeignClientsRegistrar 类,registerBeanDefinitions 方法会把 @FeignClient 注解的接口封装成 FeignClientFactoryBean 并注册为 bean 定义。供后续的初始化使用。FeignClientFactoryBean 继承了 FactoryBean。熟悉的同学应该都知道,它主要用来实例化一些一些比较复杂的类,通过它的 getObject 方法,就像我们开头讲到的,它返回的就是一个 JDK 动态类,具体的 InvocationHandler 由 InvocationHandlerFactory 生成(如果使用 熔断器,则熔断器会有自己的 InvocationHandler,例如: Sentinel 有 SentinelInvocationHandler)。有兴趣的同学可以自己下代码,这里不做具体分析了。

2. feign 整合熔断器

feign 提供了 Feign.Builder 来整合熔断器,目前 Spring 的熔断器都支持。因为 Hystrix 已经不更新了,可以选择使用阿里的 Sentinel 来做熔断器。一个重要原因是有中文文档,学习成本会比较低,而且阿里的熔断器肯定经历过千锤百炼了。

2.1 整合 Sentinel

加入依赖

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-sentinel
            2.1.0.RELEASE
        

application.yml 加入配置:

feign:
  sentinel:
    enabled: true

这样整合就可以了。

2.2 如何使用?

示例:

@FeignClient(name = "ActivityClient", url = "${sys.profile-url}", path = "activity/", fallbackFactory = ActivityClient.ActivityClientHystrix.class)
public interface ActivityClient {

    @PostMapping("dispatchRewordRedPaper")
    CommonResponse dispatchRewordRedPaper(@RequestBody OrderRewordPaperRequest request);

    @Component
    class ActivityClientHystrix implements FallbackFactory {
        @Resource
        private SysConfig sysConfig;

        @Override
        public ActivityClient create(Throwable cause) {
            return request -> {
                if (cause instanceof FeignException) {
                    FeignException cause1 = (FeignException) cause;
                    if (cause1.status() == HttpStatus.UNAUTHORIZED.value()) {
                        JwtUtils.resetJwtInSystem(BaseConstants.JWT_INNER, sysConfig.getJwtSecret());
                    }
                    return new CommonResponse(cause1.status());
                } else if(cause instanceof HystrixTimeoutException){
                }{
                    return new CommonResponse();
                }
            };
        }
    }
}

只需要实现 FallbackFactory 或 Fallback 然后在 @FeignClient 中指定就可以了。其实 Fallback 内部也会被封装成 FallbackFactory。

3. Contract

Contract 表示契约,主要用来解析方法请求的注解。这也是之所以能使用 SpringMvc (例如:@RequestMapping) 注解来定义 feign 的原因。

4. 指定具体的请求框架

Feign 目前支持 HttpClient,OkHttpClient 和 LoadBalancerFeignClient(负载),具体可以看 feign.Client 的实现类。通过 Feign.Builder#client 放入注入(当然 Spring 会帮你做这些)具体请看 FeignClientFactoryBean 。

5. 注意:

  1. @FeignClient 如果不填 url,默认会使用 ribbon 负载均衡,如果没有引入 ribbon 则会报错。

你可能感兴趣的:(openfeign 记录)