OpenFeign 源码阅读 —— 动态代理创建
Feign 的魔法从"接口 → 代理"开始。本文从源码拆解:Feign.Builder 如何装配组件、ReflectiveFeign 如何构建方法处理器、ParseHandlersByName 如何解析注解、InvocationHandlerFactory 如何生成拦截器。
Feign.Builder 构建流程
Builder 接口与实现
java
// feign.Feign
public static class Builder {
private final List<RequestInterceptor> requestInterceptors = new ArrayList<>();
private Client client = new Client.Default(null, null); // 默认客户端
private Encoder encoder = new Encoder.Default(); // 默认编码
private Decoder decoder = new Decoder.Default(); // 默认解码
private Contract contract = new Contract.Default(); // 默认契约
private InvocationHandlerFactory invocationHandlerFactory = new InvocationHandlerFactory.Default();
private Retryer retryer = new Retryer.Default();
private Logger logger = new NoOpLogger();
private Logger.Level logLevel = Logger.Level.NONE;
private Request.Options options = new Request.Options();
private boolean decode404;
// 链式装配(每个 setter 返回 this)
public Builder encoder(Encoder encoder) { this.encoder = encoder; return this; }
public Builder decoder(Decoder decoder) { this.decoder = decoder; return this; }
public Builder contract(Contract contract) { this.contract = contract; return this; }
public Builder client(Client client) { this.client = client; return this; }
public Builder retryer(Retryer retryer) { this.retryer = retryer; return this; }
// 构建最终 Feign 实例
public Feign build() {
// 校验同步/异步模式,生成对应实现
if (async) return new AsyncFeign(...);
return new ReflectiveFeign(new ParseHandlersByName(contract, options, encoder, decoder, ...));
}
// 创建代理
public <T> T target(Class<T> apiType, String url) {
return build().newInstance(new Target.HardCodedTarget<>(apiType, url));
}
}关键点
- 所有组件都是可替换的(可插拔架构的核心)
build()生成ReflectiveFeign(同步)或AsyncFeign(异步)target()接收接口类型 + 服务地址(Spring 场景下地址由lb://解析)
ReflectiveFeign 核心
类结构
java
// feign.ReflectiveFeign
public class ReflectiveFeign extends Feign {
private final ParseHandlersByName targetToHandlersByName; // 方法解析器
private final InvocationHandlerFactory factory; // 拦截器工厂
public ReflectiveFeign(ParseHandlersByName targetToHandlersByName,
InvocationHandlerFactory factory) {
this.targetToHandlersByName = targetToHandlersByName;
this.factory = factory;
}
@Override
public <T> T newInstance(Target<T> target) {
// 1. 解析接口所有方法 → MethodHandler 映射
Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
// 2. 解析默认方法(default 方法)
Map<Method, MethodHandler> methodToHandler = new LinkedHashMap<>();
for (Method method : target.type().getMethods()) {
if (method.getDeclaringClass() == Object.class) continue;
MethodHandler handler = nameToHandler.get(Feign.configKey(target.type(), method));
methodToHandler.put(method, handler);
}
// 3. 创建 InvocationHandler
InvocationHandler handler = factory.create(target, methodToHandler);
// 4. JDK 动态代理
return (T) Proxy.newProxyInstance(
target.type().getClassLoader(),
new Class<?>[] { target.type() },
handler);
}
}流程拆解
newInstance(target)
├─ 1. ParseHandlersByName.apply() → 解析接口方法,生成 MethodHandler 表
├─ 2. 建立 Method → MethodHandler 映射(跳过 Object 方法)
├─ 3. InvocationHandlerFactory.create() → 拦截器
└─ 4. Proxy.newProxyInstance → 返回代理对象ParseHandlersByName 方法解析
核心类
java
// feign.ReflectiveFeign.ParseHandlersByName
static final class ParseHandlersByName {
private final Contract contract; // 契约:注解 → 方法元数据
private final MethodToMetadata toMetadata; // 元数据转换
private final Encoder encoder;
private final Decoder decoder;
private final SynchronousMethodHandler.Factory methodHandlerFactory;
public Map<String, MethodHandler> apply(Target target) {
// 1. 用 Contract 解析接口:得到每个方法的元数据
List<MethodMetadata> metadataList = contract.parseAndValidatateMetadata(target.type());
Map<String, MethodHandler> result = new LinkedHashMap<>();
for (MethodMetadata md : metadataList) {
// 2. 为每个方法构建 MethodHandler
result.put(md.configKey(), createMethodHandler(target, md));
}
return result;
}
private MethodHandler createMethodHandler(Target target, MethodMetadata md) {
// 包装成 SynchronousMethodHandler(同步调用处理器)
return methodHandlerFactory.create(target, md, invocationHandlerFactory, logger, ...);
}
}解析流程
ParseHandlersByName.apply(target)
│
├─ 1. contract.parseAndValidatateMetadata(接口)
│ └─ SpringMvcContract:解析 @GetMapping/@PathVariable 等注解
│ → 每个方法生成 MethodMetadata(方法签名、URL 模板、参数索引)
│
└─ 2. 每个方法 → SynchronousMethodHandler
└─ 处理"参数 → 请求"和"响应 → 结果"的完整逻辑SynchronousMethodHandler
每个方法的核心执行器:
java
// feign.SynchronousMethodHandler
final class SynchronousMethodHandler implements MethodHandler {
private final MethodMetadata metadata; // 方法元数据
private final Target<?> target; // 服务地址
private final Client client; // HTTP 客户端
private final Retryer retryer; // 重试策略
private final RequestTemplate.Factory buildTemplateFromArgs; // 模板工厂
private final InvocationHandlerFactory factory;
private final Logger logger;
@Override
public Object invoke(Object[] argv) throws Throwable {
// 1. 构建 RequestTemplate(把方法参数填进模板)
RequestTemplate template = buildTemplateFromArgs.create(argv);
// 2. 执行请求(含重试循环)
Response response = executeAndDecode(template);
// 3. 返回解码后的结果
return response;
}
}executeAndDecode:执行与解码
java
Object executeAndDecode(RequestTemplate template) throws Throwable {
Request request = targetRequest(template); // 1. 编码器生成 Request
// 重试循环
long start = System.nanoTime();
while (true) {
try {
Response response = client.execute(request, options); // 2. 发请求
// 3. 响应处理
if (response.status() >= 200 && response.status() < 300) {
// 成功:解码响应体(返回 null 则空体)
return decoder.decode(response, metadata.returnType());
}
// 4. 404 且配置 decode404 → 也解码
if (response.status() == 404 && decode404) { ... }
// 5. 其他错误 → 抛异常
throw new FeignException(...);
} catch (RetryableException e) {
// 可重试异常:重试器决定是否重试
Retryer.Result result = retryer.continueOrPropagate(e);
if (result == null) throw e;
request = result.getRequest(); // 用新请求重试
}
}
}InvocationHandlerFactory
接口与默认实现
java
// feign.InvocationHandlerFactory
public interface InvocationHandlerFactory {
InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch);
// 默认实现
final class Default implements InvocationHandlerFactory {
@Override
public InvocationHandler create(Target target, Map<Method, MethodHandler> dispatch) {
return new ReflectiveFeign.FeignInvocationHandler(target, dispatch);
}
}
}FeignInvocationHandler
java
// feign.ReflectiveFeign.FeignInvocationHandler
static class FeignInvocationHandler implements InvocationHandler {
private final Target target;
private final Map<Method, MethodHandler> dispatch;
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
// Object 方法特殊处理
if ("equals".equals(method.getName())) { return equals(args[0]); }
if ("hashCode".equals(method.getName())) { return hashCode(); }
if ("toString".equals(method.getName())) { return toString(); }
// 业务方法:找对应的 MethodHandler
MethodHandler handler = dispatch.get(method);
if (handler == null) {
throw new IllegalStateException("未找到方法处理器: " + method);
}
// 关键:不支持异步返回(必须同步调用)
return handler.invoke(args);
}
}Spring Cloud 的扩展
Spring Cloud OpenFeign 通过 HystrixFeign / SentinelFeign 替换 InvocationHandlerFactory,实现降级包装:
java
// spring-cloud-openfeign 中
if (fallbackFactory != null) {
invocationHandlerFactory = new FallbackFactoryInvocationHandlerFactory(...);
}完整时序回顾
Feign.builder()....target(OrderClient.class, url)
│
├─ build() → ReflectiveFeign
├─ newInstance(target)
│ ├─ ParseHandlersByName.apply():Contract 解析注解 → MethodMetadata
│ ├─ 生成 SynchronousMethodHandler(含编码器/客户端/解码器/重试器)
│ ├─ factory.create() → FeignInvocationHandler
│ └─ Proxy.newProxyInstance → 代理对象
│
└─ 返回代理(Spring 注入给调用方)
调用时:
proxy.getOrder(id) → FeignInvocationHandler.invoke()
→ SynchronousMethodHandler.invoke()
→ RequestTemplate 构建 → Encoder 编码 → Client 执行 → Decoder 解码 → 结果关键源码文件索引
| 类 | 位置 |
|---|---|
| Feign.Builder | feign-core/.../feign/Feign.java |
| ReflectiveFeign | feign-core/.../feign/ReflectiveFeign.java |
| ParseHandlersByName | ReflectiveFeign 内部类 |
| FeignInvocationHandler | ReflectiveFeign 内部类 |
| SynchronousMethodHandler | feign-core/.../feign/SynchronousMethodHandler.java |
| InvocationHandlerFactory | feign-core/.../feign/InvocationHandlerFactory.java |
| Contract | feign-core/.../feign/Contract.java |
常见问题
- 为什么接口没有实现类也能调用? JDK 动态代理:运行时生成代理类,拦截方法调用转发给 MethodHandler。
- Feign 支持 default 方法吗? 支持,default 方法直接调用实现(不走 HTTP)。
- 方法解析失败(400/404)? Contract 解析注解不匹配、参数名缺失(需
-parameters编译参数)会导致构建失败。 - 重试机制在哪一层? SynchronousMethodHandler 内
executeAndDecode的重试循环,由 Retryer 控制。