pole-java 是 Pole 的 Java 客户端运行时 monorepo,统一承载 Thin SDK 核心、
framework adapter 与薄 Java Agent。现有 Maven artifact
io.github.lattice-hub:pole-client-java 保持为 Thin SDK 核心入口。
当前已实现的 Thin SDK 负责:
- 通过
OpenControlSessiongRPC over Unix Domain Socket 与本地 Pole Sidecar 建立长期内部会话; - 接收 Sidecar 首帧主动下发的 HTTP、gRPC、Dubbo、Thrift listener 端口;
- 注册本地 ingress 服务,并读取 Sidecar 回传的注册状态;
- 向框架 adapter 提供线程安全的本地 listener 地址;
- 构造仅含
namespace、service的不可变TargetService; - 生成业务协议使用的 canonical target service 元信息。
- 传播可选的
TrafficContext流量标签,不以 trace-id 关联灰度。
| 模块 | 职责 | 发布状态 |
|---|---|---|
pole-client-java |
Thin SDK 核心、TrafficContext、UDS 控制会话和本地服务注册 | 已实现 |
pole-java-bom |
Java 模块统一版本管理 | 已实现 |
adapters/spring-cloud/pole-spring-cloud-common |
Spring Cloud LoadBalancer 共用出站行为 | 已实现 |
adapters/spring-cloud/pole-spring-cloud-boot-{2,3,4} |
按 Boot 主版本隔离的自动安装与入站适配 | 已实现 |
adapters/dubbo/pole-dubbo-3x |
Dubbo 3.x invocation attachment 流量上下文传播 | 已实现 |
adapters/grpc/pole-grpc-1x |
gRPC 1.x client/server interceptor | 已实现 |
adapters/thrift/pole-thrift-http |
Thrift-over-HTTP Header 流量上下文传播 | 已实现 |
agent/pole-agent-bootstrap |
bootstrap ClassLoader 可见的稳定事件桥 | 已实现 |
agent/pole-agent-api |
framework-neutral Agent 插件 SPI | 已实现 |
agent/pole-agent-core |
插件目录发现、独立 ClassLoader、生命周期和 payload 隔离 | 已实现 |
agent/plugins/spring-cloud-plugins |
Spring Cloud 单一入口与 3x/4x/5x 版本 provider | 已实现 |
agent/plugins/dubbo-plugins |
Dubbo 3.x Agent 插件族 | 已实现 |
agent/plugins/grpc-plugins |
gRPC 1.x Agent 插件族 | 已实现 |
agent/plugins/thrift-plugins |
Thrift-over-HTTP Agent 插件族 | 已实现 |
agent/pole-java-agent |
薄 Agent 入口与 lib/plugins 目录化分发 |
已实现 |
agent/docker |
可作为 init container 使用的 Agent artifact image | 已实现 |
核心类继续位于同一个 artifact,避免将既有 io.github.latticehub.client package
拆散到多个 JAR。adapter 是请求级行为的唯一实现;Agent 不复制目标身份、TrafficContext 或 Sidecar
连接逻辑,也不通过逐 RPC 字节码增强重复治理能力。
业务请求不经过 bootstrap gRPC 会话。框架 adapter 应把请求发送到对应协议的
127.0.0.1:{listenerPort},并注入:
latticehub-target-namespace
latticehub-target-service
- Java 17 或更高版本;
- Maven 3.8 或更高版本;
- macOS 或 Linux 等支持 JDK Unix Domain Socket 的 Unix-like 系统;
- Sidecar 与业务容器共享
/var/run/pole/sidecar目录。
SDK 使用 gRPC Java 官方 Netty transport,并通过 Java 17 的
UnixDomainSocketAddress 与 Netty NIO domain socket channel 建连。无需额外安装
Epoll/KQueue native transport,也没有平台 classifier 运行时依赖。Windows 不在 v1
支持范围内。
默认 UDS:
/var/run/pole/sidecar/bootstrap.sock
仅本地开发、测试或特殊部署可通过 POLE_SIDECAR_SOCKET 覆盖。SDK 不内置任何
业务 listener 端口。
import io.github.latticehub.client.SidecarBootstrapClient;
import io.github.latticehub.client.SidecarProtocol;
import java.net.InetSocketAddress;
try (SidecarBootstrapClient sidecar = SidecarBootstrapClient.connect()) {
InetSocketAddress grpcAddress = sidecar.listenerAddress(SidecarProtocol.GRPC);
// 把业务 gRPC channel 指向 grpcAddress。
}connect() 在初始化阶段有界等待并使用指数退避重试。可按应用启动预算覆盖参数:
import java.time.Duration;
SidecarBootstrapClient sidecar = SidecarBootstrapClient.builder()
.initializationTimeout(Duration.ofSeconds(20))
.initialBackoff(Duration.ofMillis(100))
.maxBackoff(Duration.ofSeconds(2))
.connect();Sidecar 必须把完整 listener 表作为 OpenControlSession 首帧发送,客户端首个事件为
ClientHello。SDK 验证四种协议、端口范围和协议唯一性后原子安装不可变快照。会话断开时快照立即失效,
listenerAddress 和 listenerAddresses 快速抛出 SidecarUnavailableException;
后台继续指数退避重连,新会话首帧通过后才恢复;未注销的本地服务注册会在重连后重放。
LocalServiceRegistration registration = sidecar.registerLocalService(
"payments-http", "prod", "payments", SidecarProtocol.HTTP, 8080);
sidecar.localServiceStatus(registration.getRegistrationId()).ifPresent(System.out::println);
sidecar.unregisterLocalService(registration.getRegistrationId());import io.github.latticehub.client.TargetService;
import io.github.latticehub.client.TargetServiceMetadata;
import java.util.Map;
TargetService target = TargetService.builder()
.namespace("default")
.service("orders")
.build();
Map<String, String> metadata = TargetServiceMetadata.encode(target);TargetServiceMetadata.encode(existingMetadata, target) 会按大小写不敏感方式删除调用方
已有的同名内部字段,再写入权威值,并返回不可修改 Map。值使用 canonical UTF-8
%HH 编码。
框架 adapter 的传输映射为:
- HTTP:请求 Header;
- gRPC:request Metadata;
- Dubbo:request Attachment;
- Thrift:Apache Thrift 官方 HTTP Transport 请求 Header。
TrafficContext 统一承载可选的 campaign、lane、bucket 标签。使用
TrafficContext.attach(context) 安装并在 Scope.close() 时恢复上一个上下文;
TrafficContext.current() 在未安装时返回空值。TargetServiceMetadata.encode 可接收显式
TrafficContext,显式值优先于 current,并在同一出站装配点更新 baggage:旧的
latticehub.traffic.* 成员被覆盖,外部成员继续下游传播;无结果时删除 Header。
opentelemetry-api 是 Maven optional 依赖。运行时存在该类库时可调用
TrafficContext.tryInstallOpenTelemetryBridge(),同时把领域上下文及 version、campaign、lane、
bucket 写入 OTel Context/Baggage,标准 W3C Baggage Propagator 可直接发送;领域值缺失时会从
合法 OTel Baggage 恢复。缺失 OTel 时核心类仍可加载并使用原生 ThreadLocal storage。
TrafficContext.wrap(Runnable)、wrap(Callable) 和 wrap(Executor) 可显式捕获并在 executor/
CompletableFuture 任务中恢复上下文,任务结束后恢复工作线程原值。此版本不安装 Spring、Dubbo、
gRPC 或 HTTP 框架自动 hook,也不负责重复 inject。
TrafficContext 构造与 Baggage 编解码失败时抛出 TrafficContextException。该异常继续继承
IllegalArgumentException 以保持现有 catch 兼容,并通过 getCode() 返回稳定的 conformance
机器码;getDiagnostic() 返回对应的 TrafficContextDiagnostic 枚举。
显式依赖按 Spring Boot 主版本选择且只能选择一个:
<dependency>
<groupId>io.github.lattice-hub</groupId>
<artifactId>pole-spring-cloud-boot-3</artifactId>
<version>${pole.version}</version>
</dependency>当前支持矩阵为 Boot 2.7.18、3.5.16、4.1.0,统一要求 JDK 17。三代模块注册同一套
Spring Cloud LoadBalancer request transformer:保留原 path/query,把目的地址改写为 Sidecar
HTTP listener,并写入 target service Header 与 W3C Baggage。Servlet 入站 Filter 与 WebFlux
入站 WebFilter 提取 TrafficContext,请求结束后恢复原值;非法保留字段返回 HTTP 400。
TaskDecorator、Boot task executor customizer 与 Reactor scheduler hook 负责跨异步边界传播。
namespace 依次读取 pole.namespace、POD_NAMESPACE,最后使用 default。
pole-java-agent 使用目录化分发,不再把 API、core、框架插件和 adapter payload 全部 shade
进一个大 JAR:
pole-java-agent/
├── pole-java-agent.jar
├── lib/
│ ├── pole-agent-api-*.jar
│ └── pole-agent-core-*.jar
└── plugins/
├── spring-cloud-plugins/
├── dubbo-plugins/
├── grpc-plugins/
└── thrift-plugins/
├── spring-cloud-plugin-*.jar
├── spring-cloud-3x-plugin-*.jar
├── spring-cloud-4x-plugin-*.jar
└── spring-cloud-5x-plugin-*.jar
入口 JAR 只负责 premain、安装 bootstrap bridge、定位 lib/ 并启动 core。core 从
plugins/ 发现插件族,每个顶层 JAR 或子目录使用独立 ClassLoader;Spring Cloud 入口只安装一次
instrumentation,再按 Boot major 初筛并结合 Spring Cloud major/API 从 3x/4x/5x provider 中选择
payload。core 不引用 Spring、Dubbo、gRPC 或 Thrift,也不预埋协议版本逻辑。
java -javaagent:/opt/pole/java-agent/pole-java-agent.jar -jar application.jarAgent 在 SpringApplication 加载时识别 Boot 主版本并安装对应 initializer。它不做逐请求字节码
增强;请求改写、TrafficContext 与 Sidecar 连接仍由和显式依赖完全相同的 adapter 实现。Agent
必须在 JVM 启动时通过 -javaagent 提供,不支持应用启动后的动态 attach。
Dubbo 3.x 使用 invocation attachment 传播 W3C Baggage;gRPC 1.x 自动安装 client/server
interceptor;Thrift 仅支持 THttpClient/TServlet 的 Thrift-over-HTTP Header 传播。原生
Framed + Binary/Compact/Multiplexed 没有通用 metadata carrier,因此不修改帧格式,也不宣称
支持透明 TrafficContext 传播。
Agent 也可构建为携带完整目录分发的多架构 artifact image:
docker buildx build --platform linux/amd64,linux/arm64 \
-f agent/docker/Dockerfile -t pole-java-agent:local .镜像固定提供 /opt/pole/java-agent/pole-java-agent.jar、lib/ 和 plugins/,适合由
Kubernetes init container 整体复制到业务容器共享卷;它不是应用运行时镜像,不负责启动业务 JVM。
contract/ vendoring 了当前 specification 工作树中的:
api/v1/sidecar/bootstrap.proto;thin-sdk/bootstrap/v1/README.md;thin-sdk/target-service/v1/README.md、schema 和 conformance vectors。thin-sdk/traffic-context/v1/README.md、schema 和 conformance vectors。
来源状态记录在 contract/VERSION,校验和记录在
contract/SHA256SUMS。
mvn clean verifyreactor 测试包含真实 gRPC over UDS 集成、首帧校验、断联失效、重连恢复、初始化超时、 TargetService 输入校验、canonical 编码一致性,以及 Spring Boot 2/3/4 自动配置验证。