openfeign02-源码阅读简单总结
OpenFeign使用主要是两个部分:
第一个部分:@FeignClient注解的类及类配置信息加入进beanFactory
扫描路径,加载注解类到bean工厂,并对bean进行配置
- 1.FeignClient注册入口
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
- 2.获取扫描路径,并根据
@FeignClient
注解进行扫描,获取定义的Feignbean对象
public void registerFeignClients(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
LinkedHashSet<BeanDefinition> candidateComponents = new LinkedHashSet<>();
Map<String, Object> attrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName());
//指定client类的情况下
final Class<?>[] clients = attrs == null ? null : (Class<?>[]) attrs.get("clients");
//不指定client类的情况下,通过扫描导入
if (clients == null || clients.length == 0) {
ClassPathScanningCandidateComponentProvider scanner = getScanner();
scanner.setResourceLoader(this.resourceLoader);
//导入包含FeignClient注解的类
scanner.addIncludeFilter(new AnnotationTypeFilter(FeignClient.class));
//扫描路径,获取定义的bean
Set<String> basePackages = getBasePackages(metadata);
for (String basePackage : basePackages) {
candidateComponents.addAll(scanner.findCandidateComponents(basePackage));
}
}
else {
for (Class<?> clazz : clients) {
candidateComponents.add(new AnnotatedGenericBeanDefinition(clazz));
}
}
for (BeanDefinition candidateComponent : candidateComponents) {
if (candidateComponent instanceof AnnotatedBeanDefinition beanDefinition) {
// verify annotated class is an interface
AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface");
Map<String, Object> attributes = annotationMetadata
.getAnnotationAttributes(FeignClient.class.getCanonicalName());
String name = getClientName(attributes);
String className = annotationMetadata.getClassName();
registerClientConfiguration(registry, name, className, attributes.get("configuration"));
registerFeignClient(registry, annotationMetadata, attributes);
}
}
}
- 3.注册FeignClient的bean到FeignClientFactoryBean工厂中,并给bean增加注解中配置的各个属性
给创建的FeignClient的bean对象增加url,path,name等配置的属性
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
Map<String, Object> attributes) {
String className = annotationMetadata.getClassName();
//主要是根据属性懒解析的配置,进行两种不同的逻辑处理,出路过程大致相同
if (String.valueOf(false).equals(
environment.getProperty("spring.cloud.openfeign.lazy-attributes-resolution", String.valueOf(false)))) {
eagerlyRegisterFeignClientBeanDefinition(className, attributes, registry);
}
else {
lazilyRegisterFeignClientBeanDefinition(className, attributes, registry);
}
}
第二部分:通过FeignBeanFactory获取对应的Feign的Proxy代理类
这一块内容的核心点是从FeignClientFactoryBean类的getObject方法开始,获取Feign接口的代理类
org.springframework.cloud.openfeign.FeignClientFactoryBean#getObject
<T> T getTarget() {
FeignClientFactory feignClientFactory = beanFactory != null ? beanFactory.getBean(FeignClientFactory.class)
: applicationContext.getBean(FeignClientFactory.class);
//创建Feign的建造器,Feign的配置相关的都是在这个方法中完成的
Feign.Builder builder = feign(feignClientFactory);
//如果通过注册中心转发请求的时候的处理
if (!StringUtils.hasText(url) && !isUrlAvailableInConfig(contextId)) {
if (!name.startsWith("http://") && !name.startsWith("https://")) {
url = "http://" + name;
}
else {
url = name;
}
url += cleanPath();
return (T) loadBalance(builder, feignClientFactory, new HardCodedTarget<>(type, name, url));
}
if (StringUtils.hasText(url) && !url.startsWith("http://") && !url.startsWith("https://")) {
url = "http://" + url;
}
// 获取请求Client,有几种形式
Client client = getOptional(feignClientFactory, Client.class);
if (client != null) {
if (client instanceof FeignBlockingLoadBalancerClient) {
client = ((FeignBlockingLoadBalancerClient) client).getDelegate();
}
if (client instanceof RetryableFeignBlockingLoadBalancerClient) {
client = ((RetryableFeignBlockingLoadBalancerClient) client).getDelegate();
}
builder.client(client);
}
applyBuildCustomizers(feignClientFactory, builder);
Targeter targeter = get(feignClientFactory, Targeter.class);
//这里就是创建实例的部分,具体在第三部分进行分析
return targeter.target(this, builder, feignClientFactory, resolveTarget(feignClientFactory, contextId, url));
}
第三部分:代理类执行方法调用接口
如何将Feign配置的路径等组装,远程调用
feign.ReflectiveFeign.FeignInvocationHandler
就是Feign代理类调用程序的实现类
public <T> T newInstance(Target<T> target, C requestContext) {
********************* 省略
//这里获取目标类的方法执行类
Map<Method, InvocationHandlerFactory.MethodHandler> methodToHandler = this.targetToHandlersByName.apply(target, requestContext);
//这里的获取代理类的执行类,也就是FeignInvocationHandler
InvocationHandler handler = this.factory.create(target, methodToHandler);
T proxy = Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);
********************** 省略
return proxy;
}
获取调用方法的Handler,组装请求及调用接口
- 1.获取MethodHandler
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (!"equals".equals(method.getName())) {
******************************** 省略
else {
//这里是MethodHandler调用方法,也是执行的核心逻辑部分
return ((InvocationHandlerFactory.MethodHandler)this.dispatch.get(method)).invoke(args);
}
} else {
*************************** 省略
}
}
- 2.组装请求实体及调用,以同步调用代码为例
public Object invoke(Object[] argv) throws Throwable {
//创建请求Template
RequestTemplate template = this.buildTemplateFromArgs.create(argv);
//获取请求Options
Request.Options options = this.findOptions(argv);
//请求调用
while(true) {
try {
return this.executeAndDecode(template, options);
} catch (RetryableException var9) {
// 代码重试
**********************省略
}
}
}
- 3.提供了三种发送远程请求的方式
- 负载均衡,默认的,还有同步发送多个请求的类型
public Response execute(Request request, Request.Options options) throws IOException {
HttpURLConnection connection = this.convertAndSend(request, options);
return this.convertResponse(connection, request);
}
总结:OpenFeign的内部逻辑还是挺多的,后续再根据阅读情况进一步补充
分类:
SpringCloud
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏