openfeign 只有接口如何创建bean的
OpenFeign 能够为纯接口创建 Spring Bean,其核心机制是通过动态代理和 Spring 的 FactoryBean
机制实现的。以下是详细的工作原理:
1. @EnableFeignClients
注解的启动
在 Spring Boot 主类上添加 @EnableFeignClients
注解:
@SpringBootApplication
@EnableFeignClients
public class Application { ... }
此注解会触发以下操作:
扫描所有被
@FeignClient
标记的接口。为每个接口注册一个特殊的
FeignClientFactoryBean
。
2. FeignClientFactoryBean
的作用
FeignClientFactoryBean
实现了 Spring 的 FactoryBean
接口,核心方法是 getObject()
:
public class FeignClientFactoryBean implements FactoryBean<Object> {@Overridepublic Object getObject() {return getTarget(); // 创建动态代理}private <T> T getTarget() {// 1. 构建 Feign 客户端Feign.Builder builder = feign(context);// 2. 生成动态代理return (T) targeter.target(this, builder, context, new HardCodedTarget<>(type, name, url));}
}
3. 动态代理的创建过程
当 Spring 容器需要注入 Feign 客户端时,会调用 getObject()
方法:
(1) 构建 Feign 实例
解析接口上的注解(如
@RequestMapping
,@GetMapping
)。配置编码器/解码器(如 JSON 转换)。
集成负载均衡(如 Ribbon)或服务发现(如 Eureka)。
(2) 生成代理对象
通过 ReflectiveFeign
创建 JDK 动态代理:
public class ReflectiveFeign extends Feign {public <T> T newInstance(Target<T> target) {// 为每个方法创建 MethodHandlerMap<Method, MethodHandler> methodHandlers = ...;// 生成代理InvocationHandler handler = new FeignInvocationHandler(target, methodHandlers);return (T) Proxy.newProxyInstance(target.type().getClassLoader(),new Class<?>[] {target.type()},handler);}
}
4. 代理的执行逻辑
当调用接口方法时,动态代理拦截请求:
class FeignInvocationHandler implements InvocationHandler {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) {// 1. 解析方法注解和参数RequestTemplate template = buildTemplateFromArgs(method, args);// 2. 发送 HTTP 请求Response response = client.execute(template, options);// 3. 解码响应return decoder.decode(response, method.getReturnType());}
}
5. Spring Bean 的注册
Bean 类型:代理对象(实现原始接口的 JDK Proxy)。
Bean 名称:默认取接口全限定名,或通过
@FeignClient(name="serviceName")
指定。依赖注入:通过
@Autowired
注入时,实际注入的是动态代理对象:@Autowired private UserServiceClient userService; // 实际为 Proxy 实例
关键组件总结
组件 作用 @EnableFeignClients
启动 Feign 扫描和动态代理生成 FeignClientFactoryBean
Spring 的 FactoryBean,负责创建代理 ReflectiveFeign
生成 JDK 动态代理 FeignInvocationHandler
代理逻辑:解析注解 → 构造请求 → 发送 HTTP 调用 LoadBalancerFeignClient
集成负载均衡(如 Ribbon) 补充说明
无实现类的原理
动态代理在运行时生成接口的实现类($Proxy0
),无需手动编写实现代码。HTTP 请求的发送
底层使用可插拔的 HTTP 客户端(默认HttpURLConnection
,可替换为 OkHttp 或 Apache HttpClient)。与 Spring 的整合
通过FeignContext
维护独立的配置上下文(如编解码器、拦截器)。sequenceDiagramparticipant Springparticipant FeignFactoryparticipant DynamicProxyparticipant HTTP_ClientSpring->>FeignFactory: 需要注入 UserServiceClientFeignFactory->>DynamicProxy: 创建代理对象DynamicProxy-->>Spring: 返回 Proxy 实例Spring->>Service: 注入 ProxyService->>DynamicProxy: 调用 userService.getUser()DynamicProxy->>HTTP_Client: 构造 HTTP 请求HTTP_Client->>Remote: 发送 GET /userRemote-->>HTTP_Client: 返回 JSON 数据HTTP_Client->>DynamicProxy: 响应结果DynamicProxy->>Service: 返回 User 对象
通过这种设计,OpenFeign 实现了声明式 HTTP 客户端:开发者只需定义接口,框架自动处理 HTTP 通信、负载均衡和序列化。