惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Security Blog
Microsoft Security Blog
量子位
大猫的无限游戏
大猫的无限游戏
酷 壳 – CoolShell
酷 壳 – CoolShell
IT之家
IT之家
博客园 - 三生石上(FineUI控件)
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - Franky
美团技术团队
Last Week in AI
Last Week in AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
人人都是产品经理
人人都是产品经理
罗磊的独立博客
Jina AI
Jina AI
小众软件
小众软件
S
SegmentFault 最新的问题
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
雷峰网
雷峰网
博客园 - 聂微东
博客园_首页
The Cloudflare Blog
WordPress大学
WordPress大学
Apple Machine Learning Research
Apple Machine Learning Research
有赞技术团队
有赞技术团队

博客园 - wasp

2026 研发管理者从 TL 到“AI 协作架构师”的转型指南 拯救草台班子-破局“文档式”管理:构建以工具链为载体的研发全流程闭环 《2026,不做草台班子》有感 DolphinScheduler 工作原理与使用指南 LiteFlow 框架全景解析:从入门到精通的技术内幕 AI时代代码质量提升实战指南:别让效率成为质量的敌人 LiteFlow 框架分析系列(一):工作原理与快速入门 拯救草台班子-战略制定 AgentScope Java 核心架构深度解析 AgentScope深入分析-LLM&MCP AgentScope深入学习-总体认识 大厂生存启示录:从“螺丝钉”到“金牌个人”的 9 次关键跃迁 WebMVC 与 WebFlux 模式对比分析 Spring Cloud Gateway 源码分析一 Spring Cloud Gateway WebFlux 模式架构分析 Hudi 文件格式分析 Hudi 数据模型分析 Apache Hudi 项目总体分析 Spring AI 代码分析(十)--Spring Boot集成 Spring AI 代码分析(九)--记忆能力实现
按DDD领域分析Openfeign
wasp · 2025-12-10 · via 博客园 - wasp

按DDD领域分析Openfeign

请关注微信公众号:阿呆-bot

1. 入口类及说明

1.1 入口类:Feign 和 ReflectiveFeign

Feign 是抽象工厂类,ReflectiveFeign 是其基于反射的实现,负责创建 HTTP API 代理实例。

public abstract class Feign {
  public static Builder builder() {
    return new Builder();
  }
  public abstract <T> T newInstance(Target<T> target);
}

public class ReflectiveFeign<C> extends Feign {
  public <T> T newInstance(Target<T> target) {
    Map<Method, MethodHandler> methodToHandler = 
        targetToHandlersByName.apply(target, requestContext);
    InvocationHandler handler = factory.create(target, methodToHandler);
    return (T) Proxy.newProxyInstance(
        target.type().getClassLoader(), new Class<?>[] {target.type()}, handler);
  }
}

2. DDD 业务域划分

Core 模块可以划分为以下业务域:

2.1 契约域(Contract Domain)

职责: 解析接口方法上的注解,生成方法元数据。

核心类:

  • Contract: 契约接口
  • BaseContract: 基础契约实现
  • DeclarativeContract: 声明式契约基类
  • Contract.Default: 默认契约实现
  • MethodMetadata: 方法元数据

领域边界: 负责将 Java 接口方法转换为 HTTP 请求元数据,不涉及实际的 HTTP 请求执行。

PlantUML 类关系图

image.png

2.2 方法处理域(MethodHandler Domain)

职责: 处理接口方法的调用,执行 HTTP 请求并解码响应。

核心类:

  • MethodHandler: 方法处理器接口
  • SynchronousMethodHandler: 同步方法处理器
  • AsynchronousMethodHandler: 异步方法处理器
  • DefaultMethodHandler: 默认方法处理器(处理接口默认方法)
  • MethodHandlerConfiguration: 方法处理器配置

领域边界: 负责方法调用的执行流程,包括请求构建、HTTP 执行、响应处理,但不涉及注解解析。

PlantUML 类关系图

image.png

2.3 客户端域(Client Domain)

职责: 执行实际的 HTTP 请求,是 Feign 与底层 HTTP 库的抽象。

核心类:

  • Client: HTTP 客户端接口
  • Client.Default: 默认实现(基于 HttpURLConnection)
  • AsyncClient: 异步客户端接口

领域边界: 负责 HTTP 请求的执行,不涉及请求构建和响应解码。

PlantUML 类关系图

image.png

2.4 编解码域(Encoder/Decoder Domain)

职责: 将 Java 对象编码为 HTTP 请求体,将 HTTP 响应体解码为 Java 对象。

核心类:

  • Encoder: 编码器接口
  • Encoder.Default: 默认编码器
  • Decoder: 解码器接口
  • Decoder.Default: 默认解码器
  • ErrorDecoder: 错误解码器接口

领域边界: 负责对象序列化和反序列化,不涉及 HTTP 传输。

PlantUML 类关系图

image.png

2.5 目标域(Target Domain)

职责: 表示要调用的远程 HTTP 服务,包含服务类型、名称和基础 URL。

核心类:

  • Target: 目标接口
  • Target.HardCodedTarget: 硬编码目标实现
  • Target.EmptyTarget: 空目标实现

领域边界: 负责目标服务的表示和请求模板的应用,不涉及具体的 HTTP 请求执行。

PlantUML 类关系图

image.png

2.6 请求模板域(RequestTemplate Domain)

职责: 构建 HTTP 请求模板,支持 URI 模板表达式和参数替换。

核心类:

  • RequestTemplate: 请求模板类
  • RequestTemplate.Factory: 请求模板工厂接口(内部接口)
  • RequestTemplateFactoryResolver: 请求模板工厂解析器
  • template.UriTemplate: URI 模板
  • template.BodyTemplate: 请求体模板
  • template.HeaderTemplate: 请求头模板
  • template.QueryTemplate: 查询参数模板

领域边界: 负责请求模板的构建和参数替换,不涉及实际的 HTTP 请求发送。

PlantUML 类关系图

image.png

3. 领域间关系

3.1 领域协作流程

各业务域通过以下方式协作:

  1. 契约域方法处理域: Contract 解析注解生成 MethodMetadata,MethodHandler 使用 MethodMetadata 构建请求
  2. 方法处理域请求模板域: MethodHandler 使用 RequestTemplateFactory 创建请求模板
  3. 方法处理域客户端域: MethodHandler 调用 Client 执行 HTTP 请求
  4. 方法处理域编解码域: MethodHandler 使用 Encoder 编码请求体,使用 Decoder 解码响应体
  5. 方法处理域目标域: MethodHandler 使用 Target 应用请求模板

PlantUML 时序图:方法调用流程

image.png

4. 关键代码片段

4.1 Contract 解析方法元数据

protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
  final MethodMetadata data = new MethodMetadata();
  data.targetType(targetType);
  data.method(method);
  data.returnType(Types.resolve(targetType, targetType, method.getGenericReturnType()));
  data.configKey(Feign.configKey(targetType, method));
  
  processAnnotationOnClass(data, targetType);
  for (final Annotation methodAnnotation : method.getAnnotations()) {
    processAnnotationOnMethod(data, methodAnnotation, method);
  }
  
  // 处理参数注解
  for (int i = 0; i < parameterAnnotations.length; i++) {
    processAnnotationsOnParameter(data, parameterAnnotations[i], i);
  }
  
  return data;
}

4.2 SynchronousMethodHandler 执行请求

public Object invoke(Object[] argv) throws Throwable {
  RequestTemplate template = methodHandlerConfiguration
      .getBuildTemplateFromArgs().create(argv);
  Options options = findOptions(argv);
  Retryer retryer = this.methodHandlerConfiguration.getRetryer().clone();
  
  while (true) {
    try {
      return executeAndDecode(template, options);
    } catch (RetryableException e) {
      retryer.continueOrPropagate(e);
      continue;
    }
  }
}

Object executeAndDecode(RequestTemplate template, Options options) throws Throwable {
  Request request = targetRequest(template);
  Response response = client.execute(request, options);
  return responseHandler.handleResponse(
      methodHandlerConfiguration.getMetadata().configKey(), 
      response,
      methodHandlerConfiguration.getMetadata().returnType(), 
      elapsedTime);
}

4.3 RequestTemplate 参数解析

public RequestTemplate resolve(Map<String, Object> variables) {
  if (variables == null || variables.isEmpty()) {
    return this;
  }
  
  RequestTemplate resolved = new RequestTemplate(this);
  if (uriTemplate != null) {
    resolved.uriTemplate = uriTemplate.expand(variables);
  }
  
  // 解析查询参数
  for (Map.Entry<String, QueryTemplate> entry : queries.entrySet()) {
    resolved.queries.put(entry.getKey(), entry.getValue().expand(variables));
  }
  
  // 解析请求头
  for (Map.Entry<String, HeaderTemplate> entry : headers.entrySet()) {
    resolved.headers.put(entry.getKey(), entry.getValue().expand(variables));
  }
  
  return resolved;
}

5. 实现关键点说明

5.1 领域驱动设计原则

Core 模块通过以下方式体现 DDD 原则:

  1. 领域边界清晰: 每个业务域职责单一,边界明确
  2. 领域模型: 每个域都有核心实体(如 Contract、MethodHandler、Client)
  3. 领域服务: 通过接口定义领域服务,支持可插拔实现
  4. 聚合根: Feign 和 ReflectiveFeign 作为聚合根,协调各领域协作

5.2 依赖倒置

各领域通过接口交互,实现依赖倒置:

  • MethodHandler 依赖 Client 接口,而非具体实现
  • Contract 生成 MethodMetadata,MethodHandler 使用 MethodMetadata
  • Encoder/Decoder 通过接口注入,支持替换

5.3 策略模式应用

各领域大量使用策略模式:

  • Contract: 支持不同的注解解析策略(Default、JAX-RS、Spring)
  • Client: 支持不同的 HTTP 客户端实现(Default、OkHttp、Apache HttpClient)
  • Encoder/Decoder: 支持不同的序列化策略(Default、Jackson、Gson)

5.4 模板方法模式

RequestTemplate 使用模板方法模式:

  • 定义请求模板结构(URI、Headers、Query、Body)
  • 支持参数替换和展开
  • 最终生成完整的 Request 对象

5.5 工厂模式

多处使用工厂模式:

  • Feign.builder(): 创建 Builder 工厂
  • MethodHandler.Factory: 创建 MethodHandler
  • RequestTemplateFactory: 创建 RequestTemplate(RequestTemplate.Factory 的内部接口)

6. 总结说明

Core 模块通过 DDD 领域划分,实现了清晰的职责分离:

  1. 契约域: 负责注解解析和元数据生成,是 Feign 声明式编程的基础
  2. 方法处理域: 负责方法调用的执行,是 Feign 的核心执行引擎
  3. 客户端域: 负责 HTTP 请求执行,是 Feign 与底层 HTTP 库的抽象
  4. 编解码域: 负责对象序列化,支持多种序列化框架
  5. 目标域: 负责目标服务表示,支持动态目标配置
  6. 请求模板域: 负责请求构建,支持灵活的 URI 模板和参数替换

各领域通过清晰的接口协作,实现了高内聚、低耦合的架构设计。这种设计使得 Feign 既灵活又可扩展,支持多种集成场景。