今天我们来看一下Springcloud的OpenFeign是怎么工作的
FeignClient创建过程
我们先来看Springboot启动时的FeignClient创建过程
来看EnableFeignClients
这里Import了FeignClientsRegistrar
我们看它对ImportBeanDefinitionRegistrar的实现
这里第一步是根据配置的路径扫描@FeignClient或使用配置的client class,第二步向Spring注册client bean
我们看到这里注册的bean类型是FeignClientFactoryBean,它有接口FactoryBean
根据Feign契约生成目标
下面我们来看FeignClientFactoryBean对FactoryBean的实现
整个过程就是根据@FeignClient的定义来创建实现bean
这里1是使用Spring LoadBalance方式,2是直接使用http url方式
这里有个插曲Feign.Builder builder = feign(feignClientFactory);是怎么来的
我们先来看FeignAutoConfiguration
继续看FeignClientFactory
它继承NamedContextFactory,并且指定了FeignClientsConfiguration
当使用NamedContextFactory.getInstance方法时,将会把指定的FeignClientsConfiguration注册到spring context
所以我们再看FeignClientsConfiguration的内部关于Feign.Builder的配置
这是当 org.springframework.cloud.client.circuitbreaker.CircuitBreaker不存在或关闭时
这时当org.springframework.cloud.client.circuitbreaker.CircuitBreaker存在且开启时
1使用默认CircuitBreakerFactory
2使用用户自定义CircuitBreakerFactory
FeignClientsConfiguration中还有很多其他bean的配置例如Retryer,这里就不再展开
以上就是Feign.Builder这个bean的来历
我们继续看FeignClientFactoryBean的getTarget
这里给client配置了重要的规范实现,
负载均衡
继续看loadBalance方法
这里的applyBuildCustomizers让用户可以使用FeignBuilderCustomizer来实现自定义的build配置,默认没有实现的bean
这里的Client是http请求执行时的处理器
它有几个配置入口自动选择其一,入口在FeignLoadBalancerAutoConfiguration
DefaultFeignLoadBalancerConfiguration
HttpClient5FeignLoadBalancerConfiguration
OkHttpFeignLoadBalancerConfiguration
这是默认配置
这是httpclient5满足条件时的配置
这是okhttpclient满足条件时的配置
这里的Targeter是创建feign client target 的不同实现
它的配置在FeignAutoConfiguration
这是默认
这是有熔断依赖时
动态代理
我们继续看Targeter创建target时的实现
最后使用JDK动态代理创建了target,而InvocationHandler则是实现了http接口的约定,它的实现类是FeignInvocationHandler,这里不再详细展开
而FeignCircuitBreakerTargeter则是在默认的基础上增加了fallback等
以上就是Springboot启动时FeignClient的创建过程
从上面的FeignLoadBalancerAutoConfiguration中我们可以看到,LoadBalance负载均衡 在创建feignClient时作为入参,在请求时将被使用
例如Client的实现之一FeignBlockingLoadBalancerClient的execute中
Springcloud负载均衡我们已经在 Springcloud 负载均衡是怎么工作的_icodegarden的博客-CSDN博客 中看过
执行顺序
我们再来看运行时Feign、CircuitBreaker、LoadBalance的执行顺序
CircuitBreaker我们以Sentinel为例
从上面feignClient的创建过程中我们知道target默认的InvocationHandler是FeignInvocationHandler
而创建target的过程是可以自定义的,例如自定义Targeter或更暴力点自定义Feign.Builder
Sentinel正是自定义了InvocationHandler的实现SentinelInvocationHandler
它的invoke方法的实现则跟FeignInvocationHandler相似,额外增加了Sentinel Entry的代码控制
而methodHandler.invoke(args);则跟FeignInvocationHandler是一样的,
methodHandler.invoke(args);将执行SynchronousMethodHandler.invoke 内执行Client.execute
Client.execute中则使用LoadBalancerClient.choose负载均衡
这样我们就知道他们的执行顺序是Feign -> CircuitBreaker -> LoadBalance