问题:
1.@FeignClient怎么解析的。
2.@FeignClient注解的接口放到spring容器里存的是什么。
3.调用@FeignClien接口的方法是怎么执行的。
1.@FeignClient怎么解析的?
首先从@EnableFeignClients入手,这个注解里面引入了FeignClientsRegistrar,这个类实现了ImportBeanDefinitionRegistrar,ImportBeanDefinitionRegistrar这个类主要是注册bean到spring容器的,所以到这里,大概猜测是解析@feignClient接口的类后,把解析的结果注册到spring容器。按照这个猜想继续往下看。
走到registerBeanDefinitions方法,有两个方法registerDefaultConfiguration,registerFeignClients。registerDefaultConfiguration主要干的事情是:如果@EnableFeignClients注解中的defaultConfiguration不为空,则注入到spring容器中。而registerFeignClients方法则是注入FeignClient的地方。
进入registerFeignClients,这里会扫描@EnableFeignClients所在类的包及其子包下的标记了@FeignClient类,调用registerFeignClient方法,将被@rFeignClient标注的接口注入到IOC容器中,注入的是FeignClientFactoryBean
2.@FeignClient注解的接口放到spring容器里存的是什么?
@FeignClient注解的接口放到spring容器里存的是什么,是一个FeignClientFactoryBean但在用@Autowired注入需要实例化的地方,spring在启动时,会调用FactoryBean的getObject方法,getObject方法主要是生成动态代理类:
从Spring上下文中,获取FeignContext这个Bean,这个bean是在哪里注册的呢?是在FeignAutoConfiguration
中注册的。 然后判断url属性是否为空,如果不为空,则生成默认的代理类;如果为空,则走负载均衡,生成带有负载均衡的代理类。那么重点关注loadBalance
方法。
首先调用getOptional
方法,这个方法就是根据contextId
,获取一个子上下文,然后从这个子上下文中查找Client bean,SpringCloud会为每一个feignClient创建一个子上下文,然后存入以contextId为key的map中(NamedContextFactory
的getContext
方法)。此处会返回LoadBalancerFeignClient
这个Client。FeignRibbonClientAutoConfiguration
会导入相关配置类。 然后会从子上下文中,查找Targeter
bean,默认返回的是DefaultTargeter
, 最后调用target
方法。
所以在@Autowired注入的时候,是注入的标记@FeignClient接口的动态代理类。当在自己的业务类中调用feign接口方法时,会调用FeignInvocationHandler
的invoke
方法。
3.那注入完成后,OpenFeign远程调用是怎样的呢?
从初始化的流程来看 feign.MethodHandler是feign.SynchronousMethodHandler,而java.lang.reflect.InvocationHandler是feign.ReflectiveFeign.FeignInvocationHandler,然后在调用方法时 首先要进入的就是feign.ReflectiveFeign.FeignInvocationHandler#invoke
下面的代码中有一个 executeAndDecode()
方法,该方法通过RequestTemplate
生成Request
请求对象,然后利用Http Client(默认)
获取response
,来获取响应信息
client.execute(request, options);
默认使用HttpURLConnection
发起远程调用,这里的client为LoadBalancerFeignClient
。看他的execute
方法,最终通过Ribbon负载均衡器发起远程调用。
标签:FeignClient,feign,调用,openfeign,spring,接口,源码,方法,浅析 From: https://www.cnblogs.com/lufei-123/p/17134069.html