# java-grpc-python **Repository Path**: duxvfeng/java-grpc-python ## Basic Information - **Project Name**: java-grpc-python - **Description**: Java → gRPC → Python 通用调用框架 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-07 - **Last Updated**: 2026-09-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Java → gRPC → Python 通用调用框架 Java 客户端通过 **一套固定 proto** 以 `service + method + JSON 参数` 的形式调用 Python 端注册的任意处理器。 **Python 新增业务方法时:零 proto 改动、零 Java 重编译**,写一个函数加一个装饰器即自动生效。 > 📖 **完整使用文档(Python handler / Java API / Spring Boot Starter / 协议与错误码参考 / FAQ)**:[docs/USAGE.md](docs/USAGE.md) ```mermaid flowchart LR J["Java 客户端
GenericGrpcClient
invoke / invokeAsync / invokeStream"] -- "GenericRequest
service+method+payload_json" --> S["Python 服务端
GenericServiceServicer
统一 dispatch"] S -- "路由" --> H1["@rpc_handler math.*"] S -- "路由" --> H2["@rpc_handler string.*"] S -- "路由" --> H3["你的业务 handler
(新增无需改框架)"] ``` ## 目录结构 ``` java-grpc-python/ ├── pom.xml # Maven 聚合根(3 个模块) ├── proto/generic_service.proto # 两端共用的唯一协议(通用信封 + 流式 + ListMethods) ├── python-server/ # Python 服务端 │ ├── .venv/ # ★ 虚拟环境(python3.12),由 setup.sh 创建 │ ├── requirements.txt │ ├── main.py # 启动入口 │ ├── scripts/{setup,start,stop}.sh │ ├── generic_rpc/ # ★ 通用框架核心(与业务无关,可直接复用) │ │ ├── registry.py # @rpc_handler 注册表;生成器 => 自动识别为流式 │ │ ├── servicer.py # dispatch、JSON 编解码、异常 → ErrorInfo、耗时统计 │ │ ├── server.py # 线程池、keepalive、健康检查、gRPC 反射、优雅关闭 │ │ ├── context.py / errors.py # RpcContext / RpcError │ ├── gen/ # grpcio-tools 生成的 stub(提交,运行无需重生成) │ └── app/ # 业务处理器:每个 .py 自动加载,_开头除外 ├── java-client/ # 核心客户端库(Maven,stub 由插件自动生成) │ └── src/main/java/com/xyyh/rpc/ │ ├── GenericGrpcClient.java # ★ 通用客户端:同步/异步/流式/原始 JSON │ ├── GrpcClientConfig.java # host/port/deadline/keepalive/重试 │ ├── GenericRpcException.java# 业务错误与传输错误统一出口 │ └── demo/ClientDemo.java # 纯 Java 端到端演示 ├── spring-boot-starter/ # ★ Spring Boot Starter(generic-rpc-spring-boot-starter) │ └── src/main/java/com/xyyh/rpc/spring/ │ ├── GenericRpcAutoConfiguration.java # 自动装配 genericGrpcClient + 健康检查 │ ├── GenericRpcProperties.java # generic.rpc.* 配置(含命名多客户端) │ ├── GenericRpcBeanRegistrar.java # @GenericRpc 接口扫描 + 命名客户端注册 │ ├── GenericRpc / RpcMethod / EnableGenericRpcClients # Feign 风格注解 │ └── GenericRpcFactoryBean / GenericRpcInvocationHandler / GenericRpcHealthIndicator └── demo-spring-app/ # Spring Boot 演示应用(REST + actuator) ``` ## 快速开始 ```bash # 1. Python 侧:创建 .venv + 装依赖 + 生成 stub(首次执行一次) cd python-server && ./scripts/setup.sh # 2. 启动服务(默认 50051;日志在 python-server/logs/server.log) ./scripts/start.sh # 停止: ./scripts/stop.sh # 3. Java 侧(全模块):编译并安装到本地仓库 cd .. && mvn -B install -DskipTests # 4a. 纯 Java 演示 cd java-client && mvn -q compile exec:java # 4b. Spring Boot 演示(REST + actuator,默认 8080 端口) cd ../demo-spring-app && mvn -B spring-boot:run # curl "http://127.0.0.1:8080/api/sum?a=12&b=30" ``` gRPC 反射已开启,调试方便:`grpcurl -plaintext 127.0.0.1:50051 list`。 ## Spring Boot Starter(推荐用法) 在你的 Spring Boot 3 应用中引入 starter,即可零样板代码使用: ```xml com.xyyh generic-rpc-spring-boot-starter 1.0.0 ``` `application.yml`: ```yaml generic: rpc: host: 127.0.0.1 port: 50051 deadline-ms: 5000 retry-attempts: 0 # UNAVAILABLE 重试次数 metadata: # 透传给 Python 的公共 metadata client: my-app clients: # 可选:命名多客户端(多 Python 服务) backup: host: 127.0.0.2 port: 50051 ``` Starter 自动装配提供: - **`genericGrpcClient` Bean**:`GenericGrpcClient` 单例,应用关闭时优雅 shutdown; 自定义同名 Bean 即可覆盖。 - **接口代理(Feign 风格)**:在主应用包(或 `@EnableGenericRpcClients(basePackages=...)` 指定的包)下声明接口,Starter 扫描后自动生成实现并注册为 Bean: ```java @GenericRpc(service = "math") public interface MathApi { @RpcMethod("sum") SumResult sum(SumParams params); // 一元 @RpcMethod("sum") CompletableFuture sumAsync(SumParams p); // 异步 @RpcMethod("fibonacci") List fibonacci(FibParams params); // 服务端流式自动收集为 List } // 直接注入使用 @Autowired MathApi mathApi; mathApi.sum(new SumParams(1, 2)).sum(); ``` 映射规则:第一个参数即 payload;返回 `T` 为一元、`CompletableFuture` 为异步、 `Iterator` / `List` 为流式、`void` 为触发即忘;`@RpcMethod` 省略时用方法名。 多客户端:接口上 `@GenericRpc(service = "order", client = "backup")`。 - **健康检查**:应用引入 actuator 后自动注册 `genericRpc` 组件 (`/actuator/health` 会真实执行一次 ListMethods,展示已注册方法数)。 完整可运行示例见 `demo-spring-app`(REST 接口 + 异常 → HTTP 502 映射)。 ## Java 端用法 ```java try (GenericGrpcClient client = GenericGrpcClient.newBuilder() .host("127.0.0.1").port(50051) .deadlineMs(5000) // 每次调用超时 .retryAttempts(2) // UNAVAILABLE 自动重试(默认 0) .metadata(Map.of("tenant", "acme")) // 透传给 Python 的公共 metadata .build()) { // 一元调用,结果映射为 POJO / Map SumResult r = client.invoke("math", "sum", Map.of("a", 12, "b", 30), SumResult.class); // 原始 JSON 字符串 String json = client.invokeForJson("string", "reverse", Map.of("text", "abc")); // 异步 CompletableFuture f = client.invokeAsync("math", "sum", Map.of("a", 1, "b", 2), SumResult.class); // 服务端流式:Python handler 每次 yield 即一帧 client.invokeStream("math", "fibonacci", Map.of("n", 8), FibItem.class) .forEachRemaining(item -> System.out.println(item.value())); // 服务发现 List methods = client.listMethods(); } ``` 错误统一抛 `GenericRpcException`:`getCode()` 为稳定错误码, `isTransportError()` 区分服务端业务错误与传输层错误(超时/断连)。 ## Python 端:新增一个业务方法(就这两步) 1. 在 `app/` 下新建任意 `.py`(或改现有文件),写 handler: ```python from generic_rpc import RpcContext, RpcError, rpc_handler @rpc_handler("order", "create", description='创建订单,入参 {"sku": "A001", "qty": 2}') def create_order(params: dict, ctx: RpcContext) -> dict: if params.get("qty", 0) <= 0: raise RpcError("数量必须为正数", code="INVALID_QTY", detail=params) return {"order_id": "O-2024-001", "operator": ctx.get_metadata("tenant")} ``` 2. 重启服务(`./scripts/stop.sh && ./scripts/start.sh`)即生效—— Java 端直接 `client.invoke("order", "create", ..., Map.class)`,无需改任何 proto/代码。 规则速记: | 写法 | 行为 | |---|---| | 普通函数 `def h(params)` / `def h(params, ctx)` | 一元调用(Invoke) | | 生成器函数(函数体含 `yield`) | 服务端流式(InvokeStream),每个 `yield` 一帧 | | 返回值任意可 JSON 序列化对象 | 自动写入 `result_json` | | 抛 `RpcError(code=..., detail=...)` | Java 端收到 `success=false` + ErrorInfo | | 抛其他异常 | 归为 `INTERNAL_ERROR`,日志含堆栈 | `params` 是解码后的 JSON(通常是 dict);`ctx` 提供 `request_id`、`metadata`、`streaming`。 ## 协议要点(proto/generic_service.proto) - `GenericRequest{request_id, service, method, payload_json, metadata}` → `GenericResponse{request_id, success, result_json, error{code,message,detail_json}, cost_ms}` - 错误模型:业务/框架错误走 `success=false + ErrorInfo` 的**正常响应**; 传输层错误走 gRPC Status。Java 端两者统一为 `GenericRpcException`。 - `ListMethods` 可在运维/自检时枚举服务端全部已注册方法。 ## 生产化建议(框架已留扩展点) - **TLS**:服务端 `add_secure_port` + SSL 凭据;客户端去掉 `usePlaintext()` (见 `GenericGrpcClient` 构造器)。 - **鉴权**:metadata 已全程透传,可在 Java 端配置公共 metadata, Python 端在 dispatch 前统一校验(扩展 `GenericServiceServicer`)。 - **注册中心/负载均衡**:客户端用 gRPC 原生 `xds:`/`dns:` target 替换 `forAddress(host, port)` 即可接入。 - **可观测性**:`GenericResponse.cost_ms`、request_id 已内置; 服务端日志格式见 `generic_rpc/servicer.py`。 - Python 侧默认 32 工作线程,流式/长任务可改 `main.py --workers`; 消息上限两端默认 32MiB。 ## 环境要求 - Java 17+ 与 Maven 3.8+(stub 由 protobuf-maven-plugin 在编译期自动生成) - Python 3.9+(`setup.sh` 优先用 python3.12 创建 `.venv`,可用 `PYTHON_BIN=python3 ./scripts/setup.sh` 指定解释器) - 已验证版本:grpcio 1.83.1 / grpc-java 1.66.0 / protobuf 3.25.5 & 6.33.6