通用工具包设计 / 公共 SDK 开发规范
SDK 整体设计
SDK 设计原则
公共 SDK 的设计遵循以下核心原则,确保其高质量、可维护且易于使用。
简单易用
API 设计遵循直观原则,降低学习成本。方法签名简洁,参数命名自解释,提供合理的默认值。使用 Builder 模式构造复杂对象,避免构造函数参数过多的问题。
// 推荐的简单易用 API 风格
SdkClient client = SdkClient.builder()
.endpoint("https://api.example.com")
.accessKey("your-access-key")
.secretKey("your-secret-key")
.region("cn-beijing")
.build();
CreateOrderRequest request = CreateOrderRequest.builder()
.productId("prod-123456")
.quantity(2)
.build();
CreateOrderResponse response = client.createOrder(request);无状态
SDK 实例本身不持有任何业务状态,每次请求所需信息均通过方法参数传入。这使得 SDK 实例可以被安全地共享和复用,也便于水平扩展。
线程安全
所有 SDK 组件必须保证线程安全。Client 实例及其内部组件(连接池、序列化器、认证器)在并发场景下需正确同步。推荐使用不可变对象和 Copy-on-Write 模式。
// 线程安全的配置设计 —— 使用不可变对象
public final class SdkConfig {
private final String endpoint;
private final Duration connectTimeout;
private final Duration readTimeout;
private final int maxRetries;
private final Map<String, String> customHeaders;
// 通过 Builder 构造,所有字段 final
private SdkConfig(Builder builder) { /* ... */ }
// 修改配置返回新实例,原实例不变
public SdkConfig withEndpoint(String endpoint) {
return new Builder(this).endpoint(endpoint).build();
}
public static Builder builder() { return new Builder(); }
public static final class Builder { /* ... */ }
}最小依赖
严格控制第三方依赖的引入。每个依赖必须有明确的引入理由,优先使用标准库和成熟稳定的小型库。避免依赖传递导致冲突。核心 SDK 模块应保持轻量。
# 推荐的最小依赖原则示例
# 核心模块 (sdk-core) 仅依赖:
# - slf4j-api (日志门面)
# - Jackson (JSON 序列化)
# - OkHttp (HTTP 传输)可测试
SDK 的每个组件都应易于单元测试。通过接口抽象和依赖注入,让测试可以方便地 mock 外部依赖。提供 Mock Server 工具辅助集成测试。
版本兼容
遵循语义化版本规范。主版本号变更表示不兼容的 API 修改,次版本号表示向下兼容的功能新增,修订号表示向下兼容的问题修正。
统一异常
SDK 层所有异常统一封装,调用方只需捕获顶层异常即可处理所有 SDK 层面的错误。
可观测
融入 OpenTelemetry 生态,支持链路追踪和指标采集。每条请求自动携带 TraceId,便于分布式环境下的问题排查。
模块划分
推荐模块结构
sdk-project/
├── sdk-core # 核心模块:基础抽象、通用工具、异常体系
├── sdk-api # API 定义:请求/响应模型、Client 接口
├── sdk-transport # 传输层:HTTP 客户端封装、连接池管理
├── sdk-serialization # 序列化层:JSON/Protobuf 等序列化实现
├── sdk-security # 安全模块:签名、认证、加密
├── sdk-spring-boot-starter # Spring Boot Starter 集成
└── sdk-example # 使用示例sdk-core
核心基础模块,包含所有模块共享的基础设施:
- 统一异常体系 (SdkException 及其子类)
- 基础接口和抽象类
- 通用工具类 (字符串、集合、IO 等)
- SPI 加载机制
- 配置管理基础类
sdk-api
业务 API 定义模块:
- 请求基类和响应基类
- 具体业务的请求/响应模型
- Client 接口定义
- 枚举和常量定义
sdk-transport
HTTP 传输模块:
- HTTP 客户端抽象接口
- OkHttp/Netty/Apache HttpClient 等实现
- 连接池管理
- 重试与超时机制
- HTTP/2 支持
sdk-serialization
序列化模块:
- 序列化器接口抽象
- JSON/Protobuf/MessagePack 等实现
- SPI 可切换
sdk-security
安全模块:
- 签名算法实现 (HMAC-SHA256 等)
- 认证信息管理
- 临时 Token 管理
- 加解密工具
sdk-spring-boot-starter
Spring Boot 集成模块:
- 自动配置
- 属性绑定
- 健康检查
- 指标导出
sdk-example
示例模块:
- 快速入门示例
- 高级用法示例
- 配置示例
与其他 SDK 模块结构对比
| 模块 | 本 SDK | AWS SDK v2 | Alibaba Cloud SDK | Azure SDK |
|---|---|---|---|---|
| 核心 | sdk-core | core | core | core |
| API | sdk-api | 按服务分模块 | 按产品分模块 | 按服务分模块 |
| 传输 | sdk-transport | http-client-spi | http | http |
| 序列化 | sdk-serialization | 内置在 core | protocol | serialization |
| 安全 | sdk-security | auth | auth | identity |
| Spring集成 | sdk-spring-boot-starter | spring-boot-starter | 无官方支持 | spring-integration |
统一异常体系
异常层次设计
SDK 异常采用分级继承结构,顶层为 SdkException,按错误来源和性质划分子类。
/**
* SDK 异常基类 —— 所有 SDK 引发的异常均继承自此
*/
public class SdkException extends RuntimeException {
private final String errorCode;
private final String errorMessage;
private final ErrorContext errorContext;
public SdkException(String errorCode, String errorMessage) {
super(errorMessage);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
this.errorContext = ErrorContext.empty();
}
public SdkException(String errorCode, String errorMessage, Throwable cause) {
super(errorMessage, cause);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
this.errorContext = ErrorContext.empty();
}
public SdkException(String errorCode, String errorMessage, ErrorContext errorContext) {
super(errorMessage);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
this.errorContext = errorContext;
}
// getters
public String getErrorCode() { return errorCode; }
public String getErrorMessage() { return errorMessage; }
public ErrorContext getErrorContext() { return errorContext; }
}异常子类体系
SdkException (RuntimeException)
├── ClientException // 客户端侧错误(参数校验、连接失败等)
├── ServerException // 服务端侧错误(业务异常、服务错误等)
├── AuthenticationException // 认证授权失败
└── ValidationException // 请求参数校验失败ClientException
由客户端自身原因导致的异常,如网络连接失败、请求超时、请求被取消等。调用方通常可以通过重试或调整配置解决。
public class ClientException extends SdkException {
public ClientException(String errorCode, String errorMessage) {
super(errorCode, errorMessage);
}
public ClientException(String errorCode, String errorMessage, Throwable cause) {
super(errorCode, errorMessage, cause);
}
public ClientException(String errorCode, String errorMessage, ErrorContext errorContext) {
super(errorCode, errorMessage, errorContext);
}
}ServerException
服务端返回错误响应时抛出的异常,包含服务端返回的错误码和错误信息。调用方应根据不同的错误码采取不同处理策略。
public class ServerException extends SdkException {
private final int httpStatusCode;
private final String requestId;
public ServerException(String errorCode, String errorMessage, int httpStatusCode, String requestId) {
super(errorCode, errorMessage);
this.httpStatusCode = httpStatusCode;
this.requestId = requestId;
}
// getters ...
}AuthenticationException
认证或授权失败时抛出,包括 AK/SK 不匹配、签名无效、Token 过期、权限不足等场景。此类异常通常不需要重试。
public class AuthenticationException extends SdkException {
public AuthenticationException(String errorCode, String errorMessage) {
super(errorCode, errorMessage);
}
}ValidationException
请求参数校验失败时抛出,用于在发送请求前快速失败(Fail-Fast),避免无效请求到达服务端。
public class ValidationException extends SdkException {
private final List<FieldViolation> violations;
public ValidationException(List<FieldViolation> violations) {
super("VALIDATION_ERROR", "Request validation failed");
this.violations = violations;
}
public List<FieldViolation> getViolations() { return violations; }
public static class FieldViolation {
private final String field;
private final String message;
// constructor & getters
}
}ErrorCode 枚举设计
错误码采用类似 HTTP 状态码的分段设计,使用 5 位数字编码:第 1 位标识错误大类,第 2-3 位标识模块,第 4-5 位标识具体错误。
错误码格式: XYYZZ
- X : 错误大类 (1=系统, 2=参数, 3=认证, 4=业务, 5=限流, 9=未知)
- YY : 模块标识 (00=通用, 01=用户, 02=订单, 03=支付, ...)
- ZZ : 具体错误 (00-99)public enum ErrorCode {
// ===== 系统错误 (1xxxx) =====
INTERNAL_ERROR("10000", "Internal server error"),
SERVICE_UNAVAILABLE("10001", "Service temporarily unavailable"),
TIMEOUT("10002", "Request timeout"),
// ===== 参数错误 (2xxxx) =====
INVALID_PARAMETER("20000", "Invalid parameter"),
MISSING_REQUIRED_PARAM("20001", "Missing required parameter"),
INVALID_FORMAT("20002", "Invalid parameter format"),
INVALID_PARAMETER_VALUE("20003", "Invalid parameter value, out of range or invalid enum"),
// ===== 认证错误 (3xxxx) =====
AUTHENTICATION_FAILED("30000", "Authentication failed"),
INVALID_ACCESS_KEY("30001", "Invalid access key"),
INVALID_SIGNATURE("30002", "Invalid signature"),
SIGNATURE_EXPIRED("30003", "Signature has expired"),
INVALID_TOKEN("30004", "Invalid or expired token"),
INSUFFICIENT_PERMISSIONS("30005", "Insufficient permissions"),
// ===== 业务错误 (4xxxx) =====
RESOURCE_NOT_FOUND("40000", "Resource not found"),
RESOURCE_EXISTS("40001", "Resource already exists"),
RESOURCE_LOCKED("40002", "Resource is locked or in use"),
RATE_LIMIT_EXCEEDED("40003", "Rate limit exceeded"),
QUOTA_EXCEEDED("40004", "Quota exceeded"),
// ===== 限流/熔断 (5xxxx) =====
FLOW_CONTROL("50000", "Request denied by flow control"),
CIRCUIT_BREAKER_OPEN("50001", "Circuit breaker is open"),
;
private final String code;
private final String message;
ErrorCode(String code, String message) {
this.code = code;
this.message = message;
}
public String getCode() { return code; }
public String getMessage() { return message; }
/**
* 根据 code 查找枚举,未找到返回 null
*/
public static ErrorCode fromCode(String code) {
for (ErrorCode ec : values()) {
if (ec.code.equals(code)) {
return ec;
}
}
return null;
}
}错误码分类原则
- 全局统一:所有服务共享同一套错误码体系,避免同一含义在不同服务中使用不同错误码
- 预留扩展:每个分类预留足够的编号空间,方便后续新增
- 可读性强:错误码本身携带分类信息,便于快速定位问题
国际化支持
错误消息支持多语言,通过 MessageSource 机制加载不同语言的错误描述。
public class I18nErrorMessageResolver {
private final MessageSource messageSource;
public I18nErrorMessageResolver(MessageSource messageSource) {
this.messageSource = messageSource;
}
public String resolve(ErrorCode errorCode, Locale locale, Object... args) {
String code = "sdk.error." + errorCode.getCode();
return messageSource.getMessage(code, args, errorCode.getMessage(), locale);
}
}兼容性保证
- 错误码一旦发布,不得变更其含义
- 新增错误码只能新增,不能复用已废弃的错误码
- 废弃的错误码在文档中标注
@deprecated,至少保留两个大版本
异常上下文
每个异常携带详细的上下文信息,便于问题排查。
/**
* 异常上下文 —— 包含错误的上下文信息
*/
public final class ErrorContext {
private final String requestId; // 请求唯一标识
private final String serviceName; // 服务名
private final String method; // 调用的 API 方法名
private final long elapsedMs; // 请求耗时(毫秒)
private final String traceId; // 分布式链路追踪 ID
private final String connectionInfo; // 连接信息(可选)
private final Map<String, String> extraParams; // 额外参数
private ErrorContext(Builder builder) {
this.requestId = builder.requestId;
this.serviceName = builder.serviceName;
this.method = builder.method;
this.elapsedMs = builder.elapsedMs;
this.traceId = builder.traceId;
this.connectionInfo = builder.connectionInfo;
this.extraParams = Collections.unmodifiableMap(
builder.extraParams != null ? new HashMap<>(builder.extraParams) : Collections.emptyMap()
);
}
// getters ...
public static ErrorContext empty() {
return new Builder().build();
}
public static Builder builder() { return new Builder(); }
public static final class Builder {
private String requestId;
private String serviceName;
private String method;
private long elapsedMs;
private String traceId;
private String connectionInfo;
private Map<String, String> extraParams;
public Builder requestId(String requestId) { this.requestId = requestId; return this; }
public Builder serviceName(String serviceName) { this.serviceName = serviceName; return this; }
public Builder method(String method) { this.method = method; return this; }
public Builder elapsedMs(long elapsedMs) { this.elapsedMs = elapsedMs; return this; }
public Builder traceId(String traceId) { this.traceId = traceId; return this; }
public Builder connectionInfo(String connectionInfo) { this.connectionInfo = connectionInfo; return this; }
public Builder extraParam(String key, String value) {
if (this.extraParams == null) {
this.extraParams = new HashMap<>();
}
this.extraParams.put(key, value);
return this;
}
public Builder extraParams(Map<String, String> extraParams) {
this.extraParams = extraParams;
return this;
}
public ErrorContext build() {
return new ErrorContext(this);
}
}
}异常使用示例
try {
CreateOrderResponse response = client.createOrder(request);
} catch (ValidationException e) {
// 参数校验失败,打印具体的字段错误
e.getViolations().forEach(v ->
logger.error("Field [{}] validation failed: {}", v.getField(), v.getMessage())
);
} catch (AuthenticationException e) {
// 认证失败,检查 AK/SK 配置
logger.error("Auth failed: code={}, message={}", e.getErrorCode(), e.getMessage());
} catch (ServerException e) {
// 服务端错误,记录 requestId 用于排查
logger.error("Server error: requestId={}, code={}, httpStatus={}",
e.getRequestId(), e.getErrorCode(), e.getHttpStatusCode());
} catch (ClientException e) {
// 客户端错误,可考虑重试
ErrorContext ctx = e.getErrorContext();
logger.error("Client error: method={}, elapsed={}ms, traceId={}",
ctx.getMethod(), ctx.getElapsedMs(), ctx.getTraceId());
} catch (SdkException e) {
// 兜底处理所有 SDK 异常
logger.error("SDK error: code={}, message={}", e.getErrorCode(), e.getMessage());
}客户端设计
客户端接口设计
接口单一职责
每个 Client 接口聚焦一个业务领域,方法命名遵循业务语义,避免过度泛化。
/**
* 订单服务的 SDK 客户端接口 —— 单一职责
*/
public interface OrderClient {
CreateOrderResponse createOrder(CreateOrderRequest request);
GetOrderResponse getOrder(GetOrderRequest request);
ListOrdersResponse listOrders(ListOrdersRequest request);
CancelOrderResponse cancelOrder(CancelOrderRequest request);
}
/**
* 支付服务的 SDK 客户端接口 —— 单一职责
*/
public interface PaymentClient {
CreatePaymentResponse createPayment(CreatePaymentRequest request);
GetPaymentResponse getPayment(GetPaymentRequest request);
RefundResponse refund(RefundRequest request);
}Builder 模式构造 Client
Client 的构造过程复杂、配置项多,使用 Builder 模式提供流畅的构造体验。
OrderClient client = OrderClient.builder()
.endpoint("https://api.example.com")
.credentialsProvider(DefaultCredentialsProvider.create())
.connectTimeout(Duration.ofSeconds(10))
.readTimeout(Duration.ofSeconds(30))
.maxRetries(3)
.build();Builder 内部实现要点:
public final class OrderClientBuilder {
// 必要参数
private String endpoint;
// 带默认值的参数
private CredentialsProvider credentialsProvider = DefaultCredentialsProvider.create();
private Duration connectTimeout = Duration.ofSeconds(5);
private Duration readTimeout = Duration.ofSeconds(15);
private Duration writeTimeout = Duration.ofSeconds(15);
private int maxRetries = 3;
private int maxConnections = 50;
private RetryPolicy retryPolicy = RetryPolicy.DEFAULT;
private List<Interceptor> interceptors = new ArrayList<>();
// 对用户隐藏的内部参数
private SerializationFacade serializationFacade = SerializationFacade.defaultInstance();
private HttpClient httpClient;
OrderClientBuilder() {}
// 链式 setter
public OrderClientBuilder endpoint(String endpoint) {
this.endpoint = Objects.requireNonNull(endpoint, "endpoint must not be null");
return this;
}
public OrderClientBuilder credentialsProvider(CredentialsProvider credentialsProvider) {
this.credentialsProvider = Objects.requireNonNull(credentialsProvider, "credentialsProvider must not be null");
return this;
}
public OrderClientBuilder connectTimeout(Duration connectTimeout) {
this.connectTimeout = connectTimeout;
return this;
}
public OrderClientBuilder readTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
return this;
}
public OrderClientBuilder maxRetries(int maxRetries) {
this.maxRetries = maxRetries;
return this;
}
public OrderClientBuilder addInterceptor(Interceptor interceptor) {
this.interceptors.add(interceptor);
return this;
}
public OrderClient build() {
// 校验必要参数
Objects.requireNonNull(endpoint, "endpoint is required");
// 构建不可变配置
SdkConfig config = SdkConfig.builder()
.endpoint(endpoint)
.connectTimeout(connectTimeout)
.readTimeout(readTimeout)
.writeTimeout(writeTimeout)
.maxRetries(maxRetries)
.maxConnections(maxConnections)
.retryPolicy(retryPolicy)
.build();
// 构建传输层
HttpClient httpClient = this.httpClient != null
? this.httpClient
: HttpClientFactory.create(config);
// 构建序列化器
SerializationFacade serialization = this.serializationFacade;
// 构建认证器
Authenticator authenticator = new HmacSha256Authenticator(credentialsProvider);
// 创建 Client 实例
return new DefaultOrderClient(config, httpClient, serialization, authenticator, interceptors);
}
}配置不可变与 Copy-on-Write
Client 配置一经构造即为不可变。若需要修改配置,通过 toBuilder() 方法基于原配置创建新实例。
// 基于已有 client 修改配置创建新 client
OrderClient newClient = client.toBuilder()
.endpoint("https://new-api.example.com")
.readTimeout(Duration.ofSeconds(60))
.build();
// Client 基类中的实现
public abstract class AbstractSdkClient {
protected final SdkConfig config;
protected AbstractSdkClient(SdkConfig config) {
this.config = config;
}
public SdkConfig getConfig() {
return config; // SdkConfig 本身是不可变的,直接返回安全
}
}连接池管理
/**
* HTTP 连接池配置
*/
public final class ConnectionPoolConfig {
private final int maxIdleConnections; // 最大空闲连接数
private final Duration keepAliveDuration; // 空闲连接的存活时间
private final int maxConnections; // 总最大连接数
private final int maxConnectionsPerRoute; // 每路由最大连接数
private final Duration connectionAcquireTimeout; // 获取连接超时
// Builder 构造 ...
public ConnectionPool buildPool() {
return new ConnectionPool(maxIdleConnections, keepAliveDuration.toMillis(), TimeUnit.MILLISECONDS);
}
}连接配置
public final class ConnectionConfig {
private final Duration connectTimeout; // 连接超时
private final Duration readTimeout; // 读取超时
private final Duration writeTimeout; // 写入超时
private final Duration connectionAcquireTimeout; // 从池获取连接超时
private final boolean tcpNoDelay; // TCP_NODELAY
private final boolean keepAlive; // TCP keep-alive
private final Proxy proxy; // 代理配置
private final SslConfig sslConfig; // SSL/TLS 配置
// Builder + 默认值 ...
}重试与超时
指数退避 + 抖动
重试策略使用指数退避算法,并在每次退避中引入随机抖动(Jitter),防止重试风暴。
public final class RetryPolicy {
private final int maxRetries; // 最大重试次数
private final Duration baseDelay; // 基础延迟
private final Duration maxDelay; // 最大延迟
private final double jitterFactor; // 抖动因子 (0.0 ~ 1.0)
private final Predicate<SdkException> retryablePredicate; // 可重试异常判定
public static final RetryPolicy DEFAULT = RetryPolicy.builder()
.maxRetries(3)
.baseDelay(Duration.ofMillis(100))
.maxDelay(Duration.ofSeconds(5))
.jitterFactor(0.2)
.retryablePredicate(ex ->
ex instanceof ClientException || // 客户端错误可重试
(ex instanceof ServerException se && se.getHttpStatusCode() >= 500) // 服务端 5xx 可重试
)
.build();
// Builder ...
private RetryPolicy(Builder builder) { /* ... */ }
public static Builder builder() { return new Builder(); }
}
/**
* 指数退避 + 抖动计算器
*/
public class BackoffCalculator {
private final RetryPolicy retryPolicy;
private final Random random = new SecureRandom();
public BackoffCalculator(RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
}
/**
* 计算第 retryAttempt 次重试的延迟时间(从 1 开始计数)
*/
public Duration calculateDelay(int retryAttempt) {
long baseMs = retryPolicy.getBaseDelay().toMillis();
long maxMs = retryPolicy.getMaxDelay().toMillis();
// 指数退避: baseDelay * 2^(attempt-1)
long exponentialDelay = (long) (baseMs * Math.pow(2, retryAttempt - 1));
// 加上抖动: delay * (1 + jitterFactor * (random - 0.5) * 2)
double jitterFactor = retryPolicy.getJitterFactor();
double jitter = 1.0 + jitterFactor * (random.nextDouble() - 0.5) * 2;
long delay = (long) (Math.min(exponentialDelay, maxMs) * jitter);
return Duration.ofMillis(Math.max(delay, 1));
}
}重试执行器
/**
* 重试执行器 —— 封装重试逻辑
*/
public class RetryExecutor {
private final RetryPolicy retryPolicy;
private final BackoffCalculator backoffCalculator;
public RetryExecutor(RetryPolicy retryPolicy) {
this.retryPolicy = retryPolicy;
this.backoffCalculator = new BackoffCalculator(retryPolicy);
}
/**
* 执行一个可能重试的操作
*/
public <T> T execute(RetryableSupplier<T> supplier) {
SdkException lastException = null;
for (int attempt = 1; attempt <= retryPolicy.getMaxRetries(); attempt++) {
try {
return supplier.get();
} catch (SdkException e) {
lastException = e;
if (!retryPolicy.getRetryablePredicate().test(e)) {
throw e; // 不可重试异常,直接抛出
}
if (attempt == retryPolicy.getMaxRetries()) {
throw e; // 已达最大重试次数,抛出
}
// 等待后退延迟
Duration delay = backoffCalculator.calculateDelay(attempt);
try {
Thread.sleep(delay.toMillis());
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new ClientException("REQUEST_INTERRUPTED", "Request interrupted during retry backoff", ie);
}
}
}
// 不应到达这里
throw lastException;
}
@FunctionalInterface
public interface RetryableSupplier<T> {
T get() throws SdkException;
}
}重试使用场景
// SDK 内部自动进行重试
public class DefaultOrderClient implements OrderClient {
private final RetryExecutor retryExecutor;
// ... 其他字段
@Override
public CreateOrderResponse createOrder(CreateOrderRequest request) {
return retryExecutor.execute(() -> {
// 1. 请求参数校验
validate(request);
// 2. 序列化请求
byte[] body = serialization.serialize(request);
// 3. 签名
HttpRequest httpRequest = buildHttpRequest(request, body);
authenticator.sign(httpRequest);
// 4. 发送请求
HttpResponse httpResponse = httpClient.send(httpRequest);
// 5. 处理响应
return handleResponse(httpResponse, CreateOrderResponse.class);
});
}
}重试注意事项
- 幂等要求:只有幂等的 API 可以安全重试。非幂等 API(如创建订单)需要业务层配合去重
- 可重试异常判定:只有网络超时、服务端 5xx 等异常才触发重试,参数错误、认证失败等不重试
- SDK 默认值与用户自定义:SDK 提供合理的默认重试策略,用户可通过 Builder 完全自定义
请求与响应模型
请求基类
/**
* 基础请求类
*/
public abstract class SdkRequest {
private final Map<String, String> headers = new HashMap<>();
private final Map<String, String> queryParams = new HashMap<>();
/**
* 请求路径(相对于 endpoint)
*/
public abstract String path();
/**
* HTTP 方法
*/
public abstract HttpMethod method();
// 添加自定义 header
public void addHeader(String name, String value) {
headers.put(name, value);
}
// 添加 query 参数
public void addQueryParam(String name, String value) {
queryParams.put(name, value);
}
public Map<String, String> getHeaders() {
return Collections.unmodifiableMap(headers);
}
public Map<String, String> getQueryParams() {
return Collections.unmodifiableMap(queryParams);
}
@Override
public String toString() {
return method() + " " + path();
}
}响应基类
/**
* 基础响应类 —— 所有响应继承此类
*/
public abstract class SdkResponse {
private String requestId; // 服务端返回的请求 ID
private int httpStatusCode; // HTTP 状态码
private Map<String, String> headers; // 响应头
public String getRequestId() { return requestId; }
public void setRequestId(String requestId) { this.requestId = requestId; }
public int getHttpStatusCode() { return httpStatusCode; }
public void setHttpStatusCode(int httpStatusCode) { this.httpStatusCode = httpStatusCode; }
public Map<String, String> getHeaders() { return headers; }
public void setHeaders(Map<String, String> headers) { this.headers = headers; }
}具体请求/响应示例
/**
* 创建订单请求
*/
public class CreateOrderRequest extends SdkRequest {
private String productId;
private int quantity;
private String clientToken; // 幂等 Token
@Override
public String path() {
return "/v1/orders";
}
@Override
public HttpMethod method() {
return HttpMethod.POST;
}
// Builder
public static Builder builder() { return new Builder(); }
public String getProductId() { return productId; }
public int getQuantity() { return quantity; }
public String getClientToken() { return clientToken; }
public static final class Builder {
private String productId;
private int quantity;
private String clientToken;
public Builder productId(String productId) { this.productId = productId; return this; }
public Builder quantity(int quantity) { this.quantity = quantity; return this; }
public Builder clientToken(String clientToken) { this.clientToken = clientToken; return this; }
public CreateOrderRequest build() {
CreateOrderRequest request = new CreateOrderRequest();
request.productId = this.productId;
request.quantity = this.quantity;
request.clientToken = this.clientToken != null ? this.clientToken : UUID.randomUUID().toString();
return request;
}
}
}
/**
* 创建订单响应
*/
public class CreateOrderResponse extends SdkResponse {
private String orderId;
private String status;
private BigDecimal totalAmount;
private Instant createdAt;
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public BigDecimal getTotalAmount() { return totalAmount; }
public void setTotalAmount(BigDecimal totalAmount) { this.totalAmount = totalAmount; }
public Instant getCreatedAt() { return createdAt; }
public void setCreatedAt(Instant createdAt) { this.createdAt = createdAt; }
}分页请求/响应
/**
* 分页请求基类
*/
public abstract class PaginatedRequest extends SdkRequest {
private int pageNum = 1;
private int pageSize = 20;
public int getPageNum() { return pageNum; }
public void setPageNum(int pageNum) { this.pageNum = pageNum; }
public int getPageSize() { return pageSize; }
public void setPageSize(int pageSize) { this.pageSize = pageSize; }
}
/**
* 分页响应基类
*/
public class PaginatedResponse<T> extends SdkResponse {
private List<T> items;
private int pageNum;
private int pageSize;
private long totalCount;
private int totalPages;
public boolean hasMore() {
return pageNum < totalPages;
}
// getters & setters ...
}
// 使用示例
public class ListOrdersRequest extends PaginatedRequest {
private String status; // 过滤条件
@Override
public String path() { return "/v1/orders"; }
@Override
public HttpMethod method() { return HttpMethod.GET; }
// getters, setters, builder ...
}
public class ListOrdersResponse extends PaginatedResponse<OrderSummary> {
// 业务字段都在基类中
}异步回调与 CompletableFuture
public interface AsyncOrderClient {
/**
* 异步创建订单,返回 CompletableFuture
*/
CompletableFuture<CreateOrderResponse> createOrderAsync(CreateOrderRequest request);
/**
* 异步创建订单,通过回调通知结果
*/
void createOrderAsync(CreateOrderRequest request, Callback<CreateOrderResponse> callback);
}
/**
* 异步回调接口
*/
@FunctionalInterface
public interface Callback<T> {
void onComplete(T result, SdkException error);
}
// 异步客户端实现
public class DefaultAsyncOrderClient implements AsyncOrderClient {
private final ExecutorService executor;
private final DefaultOrderClient delegate;
public DefaultAsyncOrderClient(DefaultOrderClient delegate, ExecutorService executor) {
this.delegate = delegate;
this.executor = executor;
}
@Override
public CompletableFuture<CreateOrderResponse> createOrderAsync(CreateOrderRequest request) {
return CompletableFuture.supplyAsync(() -> delegate.createOrder(request), executor);
}
@Override
public void createOrderAsync(CreateOrderRequest request, Callback<CreateOrderResponse> callback) {
executor.submit(() -> {
try {
CreateOrderResponse response = delegate.createOrder(request);
callback.onComplete(response, null);
} catch (SdkException e) {
callback.onComplete(null, e);
}
});
}
}响应式支持(Reactive)
对于需要背压支持的高吞吐场景,提供响应式(Reactive)客户端接口,基于 Project Reactor 或 RxJava。
// 依赖: reactor-core (可选模块)
public interface ReactiveOrderClient {
Mono<CreateOrderResponse> createOrderReactive(CreateOrderRequest request);
Flux<OrderSummary> listOrdersReactive(ListOrdersRequest request);
}序列化与传输
序列化选型
选择合适的序列化协议是 SDK 设计的关键决策之一。以下从多维度对比主流序列化方案。
序列化协议对比
| 特性 | JSON | Protobuf | MessagePack | Kryo |
|---|---|---|---|---|
| JS 友好度 | 原生支持 | 需工具链 | 需工具链 | 不友好 |
| 跨语言 | 极好 | 好 | 好 | 一般(Java为主) |
| 序列化性能 | 中等 | 高 | 高 | 极高 |
| 反序列化性能 | 中等 | 高 | 高 | 极高 |
| 压缩比 | 低(文本) | 高(二进制) | 高(二进制) | 极高 |
| Schema 要求 | 无 | 必须(.proto) | 无 | 无 |
| 可读性 | 可读 | 不可读 | 不可读 | 不可读 |
| 生态成熟度 | 极好 | 极好 | 好 | 好 |
| 安全风险 | 低 | 低 | 中 | 中(需配置) |
默认序列化器:JSON
JSON 作为默认序列化方案,平衡了跨语言兼容性、可读性和生态成熟度。使用 Jackson 库实现。
/**
* 序列化器接口 —— SPI 可扩展
*/
public interface Serializer {
/**
* 序列化对象为字节数组
*/
<T> byte[] serialize(T obj) throws SerializationException;
/**
* 反序列化字节数组为对象
*/
<T> T deserialize(byte[] data, Class<T> clazz) throws SerializationException;
/**
* 反序列化字节数组为参数化类型
*/
<T> T deserialize(byte[] data, TypeReference<T> typeRef) throws SerializationException;
/**
* 内容类型标识 (如 application/json, application/x-protobuf)
*/
String contentType();
}
/**
* JSON 序列化实现 —— 基于 Jackson
*/
public class JsonSerializer implements Serializer {
private final ObjectMapper objectMapper;
public JsonSerializer() {
this.objectMapper = new ObjectMapper();
this.objectMapper.registerModule(new JavaTimeModule());
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
this.objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
this.objectMapper.setPropertyNamingStrategy(PropertyNamingStrategies.LOWER_CAMEL_CASE);
}
public JsonSerializer(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public <T> byte[] serialize(T obj) throws SerializationException {
try {
return objectMapper.writeValueAsBytes(obj);
} catch (JsonProcessingException e) {
throw new SerializationException("SERIALIZE_FAILED", "Failed to serialize object", e);
}
}
@Override
public <T> T deserialize(byte[] data, Class<T> clazz) throws SerializationException {
try {
return objectMapper.readValue(data, clazz);
} catch (IOException e) {
throw new SerializationException("DESERIALIZE_FAILED", "Failed to deserialize object", e);
}
}
@Override
public <T> T deserialize(byte[] data, TypeReference<T> typeRef) throws SerializationException {
try {
return objectMapper.readValue(data, typeRef);
} catch (IOException e) {
throw new SerializationException("DESERIALIZE_FAILED", "Failed to deserialize object", e);
}
}
@Override
public String contentType() {
return "application/json";
}
}序列化 SPI 切换机制
通过 Java SPI 机制实现序列化器的可切换,也支持用户自定义序列化器。
// META-INF/services/com.example.sdk.serialization.Serializer
// 内容: com.example.sdk.serialization.JsonSerializer
/**
* 序列化门面 —— 统一序列化入口,支持 SPI 加载
*/
public class SerializationFacade {
private final Serializer serializer;
public SerializationFacade() {
this(loadDefaultSerializer());
}
public SerializationFacade(Serializer serializer) {
this.serializer = Objects.requireNonNull(serializer, "serializer must not be null");
}
public <T> byte[] serialize(T obj) {
return serializer.serialize(obj);
}
public <T> T deserialize(byte[] data, Class<T> clazz) {
return serializer.deserialize(data, clazz);
}
public <T> T deserialize(byte[] data, TypeReference<T> typeRef) {
return serializer.deserialize(data, typeRef);
}
public String getContentType() {
return serializer.contentType();
}
/**
* 通过 SPI 加载默认序列化器,第一个有效的序列化器优先
*/
private static Serializer loadDefaultSerializer() {
ServiceLoader<Serializer> loader = ServiceLoader.load(Serializer.class);
for (Serializer s : loader) {
return s; // 返回第一个 SPI 实现
}
return new JsonSerializer(); // 兜底使用 JSON
}
}HTTP 传输
传输层抽象
/**
* HTTP 客户端抽象接口
*/
public interface HttpClient {
/**
* 发送 HTTP 请求,返回响应
*/
HttpResponse send(HttpRequest request) throws ClientException;
/**
* 异步发送 HTTP 请求
*/
CompletableFuture<HttpResponse> sendAsync(HttpRequest request);
}
/**
* HTTP 请求封装
*/
public class HttpRequest {
private final HttpMethod method;
private final String url;
private final Map<String, String> headers;
private final byte[] body;
private final Duration readTimeout;
private final Duration connectTimeout;
// Builder ...
}
/**
* HTTP 响应封装
*/
public class HttpResponse {
private final int statusCode;
private final Map<String, List<String>> headers;
private final byte[] body;
// constructor & getters ...
}OkHttp 实现(默认传输层)
/**
* 基于 OkHttp 的 HTTP 传输实现
*/
public class OkHttpClient implements HttpClient {
private final okhttp3.OkHttpClient httpClient;
private final SerializationFacade serialization;
public OkHttpClient(SdkConfig config, SerializationFacade serialization) {
this.serialization = serialization;
ConnectionPool pool = new ConnectionPool(
config.getMaxIdleConnections(),
config.getKeepAliveDuration().toMillis(),
TimeUnit.MILLISECONDS
);
this.httpClient = new okhttp3.OkHttpClient.Builder()
.connectTimeout(config.getConnectTimeout())
.readTimeout(config.getReadTimeout())
.writeTimeout(config.getWriteTimeout())
.connectionPool(pool)
.protocols(Arrays.asList(Protocol.HTTP_2, Protocol.HTTP_1_1))
.retryOnConnectionFailure(true)
.addInterceptor(new RetryInterceptor(config.getMaxRetries()))
.addInterceptor(new TracingInterceptor())
.build();
}
@Override
public HttpResponse send(HttpRequest request) throws ClientException {
try {
okhttp3.Request okRequest = toOkHttpRequest(request);
try (Response okResponse = httpClient.newCall(okRequest).execute()) {
return toSdkResponse(okResponse);
}
} catch (SocketTimeoutException e) {
throw new ClientException("TIMEOUT", "Request timed out", e);
} catch (IOException e) {
throw new ClientException("CONNECTION_ERROR", "Failed to execute HTTP request", e);
}
}
@Override
public CompletableFuture<HttpResponse> sendAsync(HttpRequest request) {
okhttp3.Request okRequest = toOkHttpRequest(request);
CompletableFuture<HttpResponse> future = new CompletableFuture<>();
httpClient.newCall(okRequest).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
future.completeExceptionally(
new ClientException("CONNECTION_ERROR", "Async request failed", e));
}
@Override
public void onResponse(Call call, Response response) {
try {
future.complete(toSdkResponse(response));
} catch (Exception e) {
future.completeExceptionally(e);
}
}
});
return future;
}
private okhttp3.Request toOkHttpRequest(HttpRequest request) {
RequestBody body = request.getBody() != null
? RequestBody.create(request.getBody(), MediaType.parse(serialization.getContentType()))
: null;
return new okhttp3.Request.Builder()
.url(request.getUrl())
.method(request.getMethod().name(), body)
.headers(Headers.of(request.getHeaders()))
.build();
}
private HttpResponse toSdkResponse(Response okResponse) throws IOException {
byte[] body = okResponse.body() != null ? okResponse.body().bytes() : new byte[0];
return new HttpResponse(okResponse.code(), okResponse.headers().toMultimap(), body);
}
}传输层配置建议
| 配置项 | 推荐默认值 | 说明 |
|---|---|---|
| 最大连接数 | 50 | 连接池中最大连接数 |
| 每路由最大连接数 | 10 | 单个目标主机的最大连接数 |
| 最大空闲连接数 | 5 | 保持空闲的连接数 |
| 空闲连接存活时间 | 5 分钟 | 空闲连接超时回收 |
| 连接超时 | 5 秒 | 建立 TCP 连接的超时时间 |
| 读取超时 | 15 秒 | 等待响应数据的超时时间 |
| 写入超时 | 15 秒 | 发送请求数据的超时时间 |
| 获取连接超时 | 3 秒 | 从连接池获取连接的超时时间 |
| HTTP/2 | 启用 | 优先使用 HTTP/2,回退到 HTTP/1.1 |
| Keep-Alive | 启用 | TCP 长连接复用 |