Feign的整体流程
Feign的整体流程
作用
feign的作用就是根据RPC远程调用的接口生成动态代理实例,然后根据SpringMVC中的方法上的注解生成方法处理器,最终生成HTTP请求,通过feignClient发送给服务端。
整体流程
feign的整体流程:
FeignClientsRegistrar的registerFeignClient()方法
在启动类添加注解@EnableFeignClients,这个注解中导入了FeignClientsRegistrar类,FeignClientsRegistrar类的主要功能就是通过扫描@FeignClient注解创建FeignClientFactoryBean实例,然后注入到Spring容器中。
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(FeignClientFactoryBean.class);
this.validate(attributes);
definition.addPropertyValue("url", this.getUrl(attributes));
definition.addPropertyValue("path", this.getPath(attributes));
String name = this.getName(attributes);
definition.addPropertyValue("name", name);
definition.addPropertyValue("type", className);
definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.addPropertyValue("fallback", attributes.get("fallback"));
definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory"));
definition.setAutowireMode(2);
String alias = name + "FeignClient";
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
boolean primary = (Boolean)attributes.get("primary");
beanDefinition.setPrimary(primary);
String qualifier = this.getQualifier(attributes);
if (StringUtils.hasText(qualifier)) {
alias = qualifier;
}
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[]{alias});
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
}
getTarget()方法
然后代码中通过@Resource等注解使用的时候,会通过FeignClientFactoryBean的getObject()方法来获取到动态代理对象。动态代理对象的生成是通过Feign.Builder的target方法中调用build()方法生成ReflectiveFeign的实例,然后通过newInstance创建最终的RPC动态代理的实例。
<T> T getTarget() {
FeignContext context = (FeignContext)this.applicationContext.getBean(FeignContext.class);
Builder builder = this.feign(context);
String url;
if (!StringUtils.hasText(this.url)) {
if (!this.name.startsWith("http")) {
url = "http://" + this.name;
} else {
url = this.name;
}
url = url + this.cleanPath();
return this.loadBalance(builder, context, new HardCodedTarget(this.type, this.name, url));
} else {
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
this.url = "http://" + this.url;
}
url = this.url + this.cleanPath();
Client client = (Client)this.getOptional(context, Client.class);
if (client != null) {
if (client instanceof LoadBalancerFeignClient) {
client = ((LoadBalancerFeignClient)client).getDelegate();
}
builder.client(client);
}
Targeter targeter = (Targeter)this.get(context, Targeter.class);
return targeter.target(this, builder, context, new HardCodedTarget(this.type, this.name, url));
}
}
动态代理的创建
创建动态代理实例的时候,feign会先创建一个调用处理器,然后每个方法创建方法处理器,方法处理器缓存在调用处理器的dispatch集合中。动态代理实例进行方法调用的时候,Feign根据反射实例从调用处理器的dispatch集合中找到对应的方法处理器,然后进行Http请求。方法处理器生成Request请求,然后交给feign的客户端进行调用,真正使用的时候用LoadBalancerFeignClient,因为它可以进行负载均衡,它还会委托具体的client完成http请求。
总结
这篇文章主要讲了Feign的整体流程,主要是通过@EnableFeignClients注解引入FeignClientsRegistrar类,类中扫描@FeignClient注解,注入FeignClientFactoryBean实例,通过getObject()方法获取动态实例,Feign的远程调用实际上就是通过动态代理来完成的,动态代理的创建是feign根据利用反射机制创建代理对象,然后找到对应的方法处理器发起http请求
- 点赞
- 收藏
- 关注作者
评论(0)