一、Feign 实现原理 5 步曲
ReflectiveFeign.FeignInvocationHandler
下面代码均来自 openfeign-core 11.x 与 spring-cloud-openfeign 3.x,只保留“能说明原理”的最小片段。
// SpringCloud 启动时,@EnableFeignClients 会 import FeignClientsRegistrar
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(...) {
// 扫描 basePackage,拿到所有 @FeignClient 接口
for (BeanDefinition candidate : scanner.findCandidateComponents(basePackage)) {
String className = candidate.getBeanClassName();
// 给每一个接口注册一个 FactoryBean:FeignClientFactoryBean
BeanDefinitionBuilder def = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
def.addPropertyValue("type", ClassUtils.forName(className, null));
registry.registerBeanDefinition("feign." + simpleName, def.getBeanDefinition());
}
}
}
// FeignClientFactoryBean.getObject() 被 Spring 调用来创建代理
public Object getObject() throws Exception {
return feign().target(Targeter.target(this.type, this.name, this.url));
}
// SpringMvcContract 把 @GetMapping 等转成 MethodMetadata
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
MethodMetadata md = new MethodMetadata();
// 1. 解析路径
String path = processAnnotationOnClass(targetType);
path = processAnnotationOnMethod(method, path);
md.template().insert(0, path);
// 2. 解析参数
for (Parameter parameter : method.getParameters()) {
if (parameter.getAnnotation(RequestParam.class) != null) {
String name = parameter.getAnnotation(RequestParam.class).value();
md.indexToName().put(i, name);
}
}
return md;
}
// SpringEncoder 把 @RequestBody Object 转成 HttpOutputMessage
public void encode(Object requestBody, Type bodyType, RequestTemplate template) {
HttpMessageConverter converter = selectConverter(requestBody, bodyType);
ByteArrayOutputStream out = new ByteArrayOutputStream();
HttpOutputMessage msg = new HttpOutputMessage(out);
converter.write(requestBody, contentType, msg);
template.body(out.toByteArray(), Charset.forName("UTF-8"));
}
// SynchronousMethodHandler 是 InvocationHandler 的“方法级”实现
public Object invoke(Object[] argv) {
// 1. 把 MethodMetadata + 实参 → RequestTemplate
RequestTemplate template = buildTemplateFromArgs.create(argv);
// 2. 应用 RequestInterceptor(加 header、日志)
for (RequestInterceptor interceptor : requestInterceptors) {
interceptor.apply(template);
}
// 3. 转成 Request 并执行
Request request = targetRequest(template);
Response response = client.execute(request, options);
// 4. 解码
return decode(response);
}
FeignClientFactoryBean
的 BeanDefinition。 当业务代码第一次 @Autowired FooService
时,Spring 会调用 FeignClientFactoryBean#getObject()
创建真正的代理对象。 Feign.Builder
(编码器、解码器、契约、client、拦截器、logger) Feign.Builder.target()
生成 JDK 动态代理,然后注册到 Spring 容器 @EnableFeignClients
└─ FeignClientsRegistrar 扫描接口
└─ 注册 BeanDefinition(beanClass = FeignClientFactoryBean)
└─ Spring 依赖注入阶段
└─ FeignClientFactoryBean#getObject()
└─ Feign.Builder → Targeter → Proxy
└─ 返回代理对象给 Spring 容器
Feign 的原理就是“注解解析 + 动态代理 + 模板发请求”; FeignClientFactoryBean 是 Spring-Cloud 把 Feign 接入 Spring IOC 的“工厂”,负责把接口变成可注入的 Bean。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。