SpringCloudFeign原理详解
⽬录
Feign的⼤体机制
@EnableFeignClients 和 @FeignClient 注解
registerDefaultConfiguration⽅法
registerFeignClients⽅法
feign客户端的动态代理
Feign 主要是帮助我们⽅便进⾏rest api服务间的调⽤,其⼤体实现思路就我们通过标记注解在⼀个接⼝类上(注解上将包含要调⽤的接⼝信息),之后在调⽤时根据注解信息组装好请求信息,接下来基于ribbon这些负载均衡器来⽣成真实的服务地址,最后将请求发送出去;之后将接收到的结果反序列化为相关的Java对象供我们直接使⽤。下⾯我们⾛进Spring Cloud对feign 封装的源码中去了解其主要实现机制。
Feign的⼤体机制
通过在启动类上标记 @EnableFeignClients 注解来开启feign的功能,服务启动后会扫描 @FeignClient 注解标记的接⼝,然后根据扫描的注解信息为每个接⼝类⽣成feign客户端请求,同时解析接⼝⽅法中的Spring MVC的相关注解,通过专门的注解解析器识别这些注解信息,以便后⾯可以正确的组装请求参数,使⽤ Ribbon 和 Eureka 获取到请求服务的真实地址等信息,最后使⽤ http 相关组件进⾏执⾏调⽤。其⼤致流程图如下:
@EnableFeignClients 和 @FeignClient 注解
在EnableFeignClients 注解类中有⼀个 @Import(FeignClientsRegistrar.class)的配置
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
// 引⼊FeignClientsRegistrar 来扫描@FeignClient注解下的类
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
...
}
我们追踪代码进⼊到FeignClientsRegistrar类中,会发现FeignClientsRegistrar 类实现了ImportBeanDefinitionRegistrar(在spring context 项⽬中)接⼝,因此spring boot启动时会调⽤它的registerBeanDefinitions()⽅法,该⽅法中会扫描EnableFeignClients 和 FeignClient 注解信息并设置相关信息。
/**
* spring boot 启动时会⾃动调⽤ ImportBeanDefinitionRegistrar ⼊⼝⽅法
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata
, BeanDefinitionRegistry registry) {
/
/ 读取 @EnableFeignClients 注解中信息
registerDefaultConfiguration(metadata, registry);
// 扫描所有@FeignClient注解的类
registerFeignClients(metadata, registry);
}
registerDefaultConfiguration⽅法
在registerDefaultConfiguration()⽅法中会读取@EnableFeignClients注解信息,然后将这些信息注册到⼀个BeanDefinitionRegistry ⾥⾯去;之后feign的⼀些默认配置将通过这⾥注册的信息中取获取。registerFeignClients⽅法
registerFeignClients()⽅法会扫描相关包路径(如果EnableFeignClients的basePackages没有配置,默认会直接使⽤启动类所在的包路径)下所有的@FeiginClient注解的类
springcloud和springboot然后根据@FeiginClient注解信息向BeanDefinitionRegistry⾥⾯注册bean,注意这⾥设置的bean名称⽣
成规则是使⽤服务名+SimpleName(),因此如果对⼀个服务写多个接⼝类会发⽣bean名称重复导致注册失败。所以需要增加⼀个 allow-bean-definition-overriding: true 的配置。
最后会调⽤ registerFeignClient() ⽅法注册feign客户端,这⾥的bean名称的为当前接⼝类的类路径。
其流程图如下:
feign客户端的动态代理
上⾯registerFeignClient()⽅法中在构建bean的时候,实际构建的是FeignClientFactoryBean。
BeanDefinitionBuilder definition = icBeanDefinition(FeignClientFactoryBean.class);
FeignClientFactoryBean 类对⽗类的getObject()⽅法进⾏了重写,后⾯动态代理时使⽤的就是它来获取feign client的。在这⾥会根据上⾯注解配置,同时会读取l配置信息,根据配置来设置feign的相关信息,⽐如编解码器、注解解析器、请求超时时间等;之后如果没有设置url那么就会和负载均衡器(ribbon)整合。最后会通过反射将接⼝中相关⽅法进⾏解析保存供后⾯进⾏jdk代理使⽤。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 判断是否是不需要代理的
if ("equals".Name())) {
try {
Object otherHandler =
args.length > 0 && args[0] != null ? InvocationHandler(args[0]) : null;
return equals(otherHandler);
} catch (IllegalArgumentException e) {
return false;
}
} else if ("hashCode".Name())) {
return hashCode();
} else if ("toString".Name())) {
return toString();
}
// 需要代理,执⾏代理⽅法
(method).invoke(args);
}
以上就是Spring Cloud Feign原理详解的详细内容,更多关于Spring Cloud Feign原理的资料请关注其它相关⽂章!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论