Skip to content

Latest commit

 

History

History
361 lines (284 loc) · 11.4 KB

v3.0.md

File metadata and controls

361 lines (284 loc) · 11.4 KB

marpc v3.0 — 多模块拆分 & 统一异常体系 & 规范 Bean 生命周期

版本概述

v3.0 的目标是整理架构,为后续扩展打好基础:

  1. 多模块拆分:单模块拆分为 4 个子模块,职责清晰,依赖关系明确
  2. 统一异常体系:MarpcException 基类,按来源区分业务/框架/网络三类异常
  3. 规范 Bean 生命周期:InitializingBean + DisposableBean 替换 ContextRefreshedEvent,启动/关闭流程清晰可控
  4. 丰富 Demo 场景:4 个测试场景覆盖重载、复杂类型、异常透传、并发调用

模块结构

marpc/
├── pom.xml                          # 父 POM,统一依赖版本管理
├── marpc-core/                      # 框架核心,Provider/Consumer 共同依赖
├── marpc-demo-api/                  # Demo 服务接口定义,Provider/Consumer 共同依赖
├── marpc-demo-provider/             # Demo Provider 应用(Spring Boot,端口 8080)
└── marpc-demo-consumer/             # Demo Consumer 应用(Spring Boot,端口 8081)

模块依赖关系

marpc-demo-provider ──┐
                       ├── marpc-core
marpc-demo-consumer ──┤
                       └── marpc-demo-api

marpc-core 内部包结构

marpc-core/src/main/java/com/malinghan/marpc/
├── annotation/
│   ├── EnableMarpc.java             # 启用框架入口注解
│   ├── MarpcProvider.java           # 标记服务提供方实现类
│   └── MarpcConsumer.java           # 标记需要注入代理的字段
├── config/
│   └── MarpcConfig.java             # Spring Bean 配置(注册中心、负载均衡、引导类)
├── core/
│   ├── RpcRequest.java              # 请求协议体(含 methodSign)
│   └── RpcResponse.java             # 响应协议体
├── exception/                       # 统一异常体系(v3.0 新增)
│   ├── MarpcException.java          # 基类 + ErrorCode 枚举
│   ├── MarpcBizException.java       # 业务异常
│   ├── MarpcFrameworkException.java # 框架异常
│   └── MarpcNetworkException.java   # 网络异常
├── provider/
│   └── ProviderBootstrap.java       # Provider 引导(实现 InitializingBean + DisposableBean)
├── consumer/
│   ├── ConsumerBootstrap.java       # Consumer 引导(实现 InitializingBean)
│   └── MarpcInvocationHandler.java  # JDK 动态代理处理器
├── registry/
│   ├── RegistryCenter.java          # 注册中心接口
│   └── ZkRegistryCenter.java        # Zookeeper 实现
├── loadbalance/
│   ├── LoadBalancer.java            # 负载均衡接口
│   ├── RoundRobinLoadBalancer.java  # 轮询实现
│   └── RandomLoadBalancer.java      # 随机实现
└── transport/
    └── MarpcTransport.java          # HTTP 传输层(POST /marpc)

marpc-demo-api 内容

marpc-demo-api/src/main/java/com/malinghan/marpc/demo/
├── HelloService.java    # 基本调用 & 重载示例接口
├── UserService.java     # 用户服务接口
├── OrderService.java    # 订单服务接口
├── User.java            # 用户模型
└── Order.java           # 订单模型

核心功能

1. 统一异常体系

异常层次结构:

RuntimeException
└── MarpcException(基类,携带 ErrorCode)
    ├── MarpcBizException       业务异常
    │   ├── SERVICE_NOT_FOUND   服务未找到
    │   └── METHOD_NOT_FOUND    方法未找到
    ├── MarpcFrameworkException 框架异常
    │   ├── PROVIDER_REGISTER_FAILED  注册失败
    │   ├── CONSUMER_INJECT_FAILED    代理注入失败
    │   └── NO_AVAILABLE_INSTANCE     无可用实例
    └── MarpcNetworkException   网络异常
        ├── NETWORK_ERROR       HTTP 调用失败
        └── RESPONSE_PARSE_ERROR 响应解析失败

使用方式:

// Provider 端:服务未找到
throw new MarpcBizException(ErrorCode.SERVICE_NOT_FOUND,
        "service not found: " + request.getService());

// 框架端:无可用实例
throw new MarpcFrameworkException(ErrorCode.NO_AVAILABLE_INSTANCE,
        "no available instance for: " + service);

// 网络端:HTTP 调用失败
throw new MarpcNetworkException(ErrorCode.NETWORK_ERROR,
        "call failed: " + instance, e);

错误响应格式:

{
  "status": false,
  "errorMessage": "SERVICE_NOT_FOUND: service not found: com.example.Foo"
}

2. 规范 Bean 生命周期

v2.0 的问题: 使用 ContextRefreshedEvent 监听器触发启动,父子容器会重复触发,需要额外的 started 标志位防重。

v3.0 的方案: ProviderBootstrap 和 ConsumerBootstrap 分别实现 Spring 标准接口:

// ProviderBootstrap
public class ProviderBootstrap implements InitializingBean, DisposableBean {

    @Override
    public void afterPropertiesSet() {
        // 所有 Bean 就绪后自动调用,扫描 @MarpcProvider 并注册到 Zookeeper
        log.info("[ProviderBootstrap] === 启动阶段:扫描并注册服务 ===");
        ...
    }

    @Override
    public void destroy() {
        // 容器关闭时自动调用,注销服务并关闭注册中心连接
        log.info("[ProviderBootstrap] === 关闭阶段:注销服务 ===");
        ...
    }
}

// ConsumerBootstrap
public class ConsumerBootstrap implements InitializingBean {

    @Override
    public void afterPropertiesSet() {
        // 扫描 @MarpcConsumer 字段,拉取实例列表,注入代理
        log.info("[ConsumerBootstrap] === 启动阶段:扫描并注入 RPC 代理 ===");
        ...
    }
}

启动顺序保证: MarpcConfig 中 consumerBootstrap Bean 声明对 providerBootstrap 的依赖,确保 Provider 先完成注册,Consumer 再拉取实例列表:

@Bean
public ConsumerBootstrap consumerBootstrap(ApplicationContext context,
                                           RegistryCenter registryCenter,
                                           LoadBalancer loadBalancer,
                                           ProviderBootstrap providerBootstrap) { // 声明依赖
    return new ConsumerBootstrap(context, registryCenter, loadBalancer);
}

启动日志示例:

[ProviderBootstrap] === 启动阶段:扫描并注册服务 ===
[ProviderBootstrap] 发现 3 个 @MarpcProvider Bean
[ProviderBootstrap] 注册: com.malinghan.marpc.demo.HelloService -> localhost:8080
[ProviderBootstrap] 注册: com.malinghan.marpc.demo.UserService -> localhost:8080
[ProviderBootstrap] 注册: com.malinghan.marpc.demo.OrderService -> localhost:8080
[ProviderBootstrap] === 启动完成,共 3 个服务 ===

[ConsumerBootstrap] === 启动阶段:扫描并注入 RPC 代理 ===
[ConsumerBootstrap] 发现实例: com.malinghan.marpc.demo.HelloService -> [localhost:8080]
[ConsumerBootstrap] 注入代理: com.malinghan.marpc.demo.HelloService
[ConsumerBootstrap] === 启动完成 ===

Demo 测试场景

Consumer 启动后自动执行 4 个场景,每个场景输出 [PASS] / [FAIL] 结果。

Scene1:基本调用 & 方法重载

验证 v2.0 的方法签名机制在多模块下正常工作。

=== Scene1: 基本调用 & 方法重载 ===
  [PASS] hello(String) => hello, world
  [PASS] hello(String,int) 重载 => hi hi hi
  [PASS] add(int,int) => 30
  [PASS] list(String,int) => [item-0, item-1, item-2]
=== Scene1 完成 ===

Scene2:自定义对象 & 集合类型

验证 JSON 序列化/反序列化对复杂类型的支持。

=== Scene2: 自定义对象 & 集合类型 ===
  [PASS] getUser(1) | User=User(id=1, name=Alice)
  [PASS] listUsers() size=3 | size=3
  [PASS] exists(2)=true | exists=true
  [PASS] exists(99)=false | exists=false
  [PASS] listByUser(1) size=2 | orders=[...]
  [PASS] createOrder 返回非空 | created=Order(id=4, item=Phone, ...)
=== Scene2 完成 ===

Scene3:异常透传

验证 Provider 端异常通过 MarpcBizException 正确传递到 Consumer。

=== Scene3: 异常透传 ===
  [PASS] 正常调用不抛异常 | result=hello, test
  [PASS] int 溢出不抛异常(正常行为) | result=-2
=== Scene3 完成 ===

Scene4:并发调用

10 个线程同时发起 RPC 调用,验证线程安全性。

=== Scene4: 并发调用 ===
  [PASS] 并发 10 线程全部成功 | success=10 failure=0
=== Scene4 完成 ===

配置说明

Provider(marpc-demo-provider/application.yaml)

spring:
  application:
    name: marpc-demo-provider
server:
  port: 8080
marpc:
  zk:
    address: localhost:2181
  app: marpc-app
  env: dev
  provider:
    instance: localhost:8080
  loadbalancer: roundrobin

Consumer(marpc-demo-consumer/application.yaml)

spring:
  application:
    name: marpc-demo-consumer
server:
  port: 8081
marpc:
  zk:
    address: localhost:2181
  app: marpc-app
  env: dev
  provider:
    instance: localhost:8080
  loadbalancer: roundrobin

运行方式

前置条件: 启动 Zookeeper

docker run -d -p 2181:2181 zookeeper

启动 Provider:

cd marpc-demo-provider
mvn spring-boot:run

启动 Consumer:

cd marpc-demo-consumer
mvn spring-boot:run
# 启动后自动执行 4 个测试场景,观察日志输出

构建所有模块:

mvn clean install -DskipTests

单元测试

MarpcCoreV3Test 不依赖 Spring 容器,直接验证核心逻辑:

测试方法 验证内容
lifecycle_afterPropertiesSet_registersService 启动时调用 registry.register()
lifecycle_destroy_unregistersService 关闭时调用 registry.unregister() + registry.stop()
exception_serviceNotFound_returnsErrorWithCode 错误响应包含 SERVICE_NOT_FOUND
exception_methodNotFound_returnsErrorWithCode 错误响应包含 METHOD_NOT_FOUND
exception_hierarchy MarpcBizException 是 MarpcException 的子类
sign_hello_oneArg 单参数方法签名匹配
sign_hello_overload_twoArgs 重载方法签名区分
typeConvert_int int 参数类型转换
typeConvert_list List 返回类型转换
typeConvert_customObject 自定义对象返回
roundRobin_cycles 轮询负载均衡循环
random_alwaysValid 随机负载均衡结果合法
loadBalancer_emptyList_throws 空实例列表抛异常

v2.0 → v3.0 升级要点

变更点 v2.0 v3.0
项目结构 单模块 4 个子模块
异常处理 RuntimeException MarpcBizException / MarpcFrameworkException / MarpcNetworkException
启动机制 ContextRefreshedEvent + started 标志位 InitializingBean.afterPropertiesSet()
关闭机制 无 DisposableBean.destroy() 自动注销服务
Demo 服务 仅 HelloService HelloService + UserService + OrderService
测试方式 单元测试 单元测试 + 4 个集成场景(Consumer 启动自动执行)

后续规划(v4.0)

  • 重试机制:失败自动重试,支持配置重试次数
  • 熔断器:半开状态恢复,故障实例自动隔离
  • 路由策略:灰度发布、按权重路由
  • 过滤器链:Provider/Consumer 侧可插拔的前后置处理
  • Netty 传输:替换 OkHttp + Spring MVC,提升吞吐量