按DDD领域分析Openfeign

按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 既灵活又可扩展,支持多种集成场景。

posted @ 2025-12-10 21:34  wasp  阅读(2)  评论(0)    收藏  举报