本文已参与「新人创作礼」活动,一起开启掘金创作之路。
FeignClientFactoryBean
获取Feign.Builder
FeignContext
Logger、Encoder、Decoder、Contract、Client & LoadBalancerFeignClient
Feign.Builder
获取Feign
Feign.Builder、Target & HardCodedTarget
Targeter & HystrixTargeter
Targeter#target() -> Feign.Builder#target -> builder()
MethodHandler & SynchronousMethodHandler
ParseHandersByName
Feign & ReflectiveFeign
获取Proxy
Feign#newInstance(target)
InvocationHandler & FeignInvocationHandler
Proxy proxy = Proxy.newInstance()
feign动态代理的请求处理机制
Feign动态代理进行请求的时候,根据请求的method对象,从Map<Method, MethodHandler> methodToHandler获取对应的SynchronousMethodHandler implements MethodHandler回调MethodHandler.invoke()。
除非你在@FeignClient里配置一个url属性,指定你要访问的服务的url地址,才会走我们没看的一段源码逻辑,否则的话,直接是走loadBalance()方法来生成动态代理
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
对@FeignClient注解标注的ProductFacadeServiceFeign接口进行解析,解析里面的方法,然后为每个方法创建一个SynchronousMethodHandler,也就是说每个MethodHandler对应一个专门用来处理方法的请求调用。
target.type(),是ProductFacadeServiceFeign接口
JDK动态代理,可以认为动态生成了一个类,实现ProductFacadeServiceFeign接口的匿名类,基于ProductFacadeServiceFeign接口的匿名类创建了一个实例对象(动态代理对象 T proxy),对T proxy对象所有接口方法的调用,都会交给ReflectiveFeign.FeignInvocationHandler来处理。
MethodHandler创建以及Contract解析Spring Mvc注解
ParseHandlersByName targetToHandlersByName,包含Decoder、Encoder、Contract等feign的核心组件
List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
key:HardCodedTarget(type=ProductFacadeServiceFeign, name=eureka-provider-ribbon-feign-api-impl, url= http://eureka-provider-ribbon-feign-api-impl)
key.type():HardCodedTarget类型
SpringMvcContract contract:解析接口的各种Spring Mvc注解,@RequestMappinng、@PathVariable、@RequestParam。默认情况下,feign不理解Spring Mvc的注解,Feign不知道如何处理。全都靠feign的Contract组件,来解析接口上的Spring Mvc的注解。
List<MethodMetadata> metadata:ProductFacadeServiceFeign接口中的所有方法。被SpringMvcContract组件解析,最后对每个方法都生成一个MethodMetadata,代表了这个方法的一些元数据。
MethodMetadata:
ProductFacadeServiceFeign#listProduct():
(1)configKey(方法的定义):ProductFacadeServiceFeign#listProduct()
(2)returnType(方法的返回类型):java.util.List<center.leon.eurekacommon.entity.ProductEntity>
(3)template(发送HTTP请求的模板):GET /product/facade HTTP/1.1
@RequestMapping(value = "/product/facade")
public interface ProductFacadeService {
/**
* @return
*/
@GetMapping(value = "")
List<ProductEntity> listProduct();
}
GET /product/facade HTTP/1.1:发送HTTP请求的模板,就是靠SpringMvcContract组件解析spring mvc的注解,构造出HTTP请求的模板
SpringMvcContract组件的工作原理
- 解析类上的@RequestMapping注解,获取uriTemplate的值【/product/facade】
- 解析方法上的@GetMapping注解,解析里面的value值,得到Http请求方法method是GET。uriTemplate的值【/product/facade】,method的值【GET】
- 硬编码HTTP协议,HTTP/1.1。template:GET /product/facade HTTP/1.1
- indexToName:解析的是@PathVariable注解。第一个占位符(index是0)要替换成方法入参里的id参数的值【0 -> id】。
ReflectiveFeign构建
public Feign build() {
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, decode404, closeAfterDecode, propagationPolicy);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
return new ReflectiveFeign(handlersByName, invocationHandlerFactory, queryMapEncoder);
}
在创建RefrectiveFeign的时候,就创建了一个SynchronousMethodHandler.Factory,作为SynchronousMethodHandler的工厂类。根据client, retryer, requestInterceptors, logger, logLevel, decode404, closeAfterDecode, propagationPolicy构造相应的SynchronousMethodHandler。用来封装LoadBalancerFeignClient(负责发送请求)、Retryer(负责请求重试)、logger(请求拦截器)、logLevel(日志打印)。
对每个方法都创建了一个对应的SynchronousMethodHandler,同步方法处理器,这个SynchronousMethodHandler里面封装了发送请求需要的所有的组件,LoadBalancerFeignClient(负责发送请求)、Retryer(负责请求重试)、logger(请求拦截器)、logLevel(日志打印)。
\