本文目录导读:

我来详细说明Java批量调用流程的规范化方法:
核心设计原则
1 统一接口定义
public interface BatchProcessor<T, R> {
/**
* 批量处理请求
* @param requests 请求列表
* @return 处理结果
*/
BatchResult<R> process(List<T> requests);
}
2 参数校验规范
public class BatchRequestValidator {
public static <T> void validate(List<T> requests, int maxBatchSize) {
if (requests == null || requests.isEmpty()) {
throw new IllegalArgumentException("请求列表不能为空");
}
if (requests.size() > maxBatchSize) {
throw new IllegalArgumentException("批量请求数量超过限制: " + maxBatchSize);
}
}
}
完整实现示例
1 批量调用框架
@Component
public class BatchInvoker {
// 配置参数
@Value("${batch.max-size:100}")
private int maxBatchSize;
@Value("${batch.timeout:5000}")
private int timeout;
@Value("${batch.retry-times:3}")
private int retryTimes;
private final ExecutorService executorService;
public BatchInvoker() {
this.executorService = Executors.newFixedThreadPool(
Runtime.getRuntime().availableProcessors() * 2
);
}
/**
* 执行批量调用
*/
public <T, R> BatchResult<R> execute(
List<T> requests,
Function<List<T>, List<R>> handler,
BatchConfig config) {
// 1. 参数校验
BatchRequestValidator.validate(requests, config.getMaxBatchSize());
// 2. 分批处理
List<List<T>> batches = partition(requests, config.getBatchSize());
// 3. 异步执行
List<CompletableFuture<List<R>>> futures = batches.stream()
.map(batch -> CompletableFuture.supplyAsync(() ->
executeWithRetry(batch, handler, config), executorService))
.collect(Collectors.toList());
// 4. 等待结果
try {
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.get(config.getTimeout(), TimeUnit.MILLISECONDS);
} catch (Exception e) {
// 超时处理
futures.forEach(f -> f.cancel(true));
return BatchResult.timeout();
}
// 5. 合并结果
return mergeResults(futures);
}
/**
* 带重试的执行
*/
private <T, R> List<R> executeWithRetry(
List<T> batch,
Function<List<T>, List<R>> handler,
BatchConfig config) {
Exception lastException = null;
for (int i = 0; i < config.getRetryTimes(); i++) {
try {
return handler.apply(batch);
} catch (Exception e) {
lastException = e;
// 退避策略
if (i < config.getRetryTimes() - 1) {
sleep(config.getRetryInterval());
}
}
}
throw new BatchException("批量处理失败", lastException);
}
}
2 统一结果封装
@Data
@Builder
public class BatchResult<T> {
private boolean success;
private List<T> data;
private Map<Integer, String> errors; // 索引 -> 错误信息
private int totalCount;
private int successCount;
private int failCount;
private long costTime;
public static <T> BatchResult<T> success(List<T> data) {
return BatchResult.<T>builder()
.success(true)
.data(data)
.totalCount(data.size())
.successCount(data.size())
.failCount(0)
.build();
}
public static <T> BatchResult<T> timeout() {
return BatchResult.<T>builder()
.success(false)
.data(Collections.emptyList())
.errors(Collections.singletonMap(-1, "批量处理超时"))
.totalCount(0)
.successCount(0)
.failCount(1)
.build();
}
}
配置管理规范
1 批量配置类
@Data
@ConfigurationProperties(prefix = "batch")
public class BatchProperties {
private int defaultBatchSize = 50;
private int maxBatchSize = 100;
private int timeout = 5000;
private int retryTimes = 3;
private int retryInterval = 100; // ms
private boolean circuitBreaker = true;
private int circuitBreakerThreshold = 10;
}
2 监控配置
@Component
@Slf4j
public class BatchMonitor {
@Autowired
private MeterRegistry meterRegistry;
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 记录批量调用指标
*/
public void recordMetrics(BatchResult<?> result, String batchType) {
// 记录计数器
Counter.builder("batch.invoke.count")
.tag("type", batchType)
.tag("status", result.isSuccess() ? "success" : "fail")
.register(meterRegistry)
.increment();
// 记录耗时
Timer.builder("batch.invoke.time")
.tag("type", batchType)
.register(meterRegistry)
.record(result.getCostTime(), TimeUnit.MILLISECONDS);
// 记录失败详情
if (result.getFailCount() > 0) {
log.warn("Batch {} has {} failures", batchType, result.getFailCount());
recordFailures(batchType, result);
}
}
}
异常处理规范
1 自定义异常体系
public class BatchException extends RuntimeException {
private BatchErrorCode errorCode;
private Map<String, Object> context;
public BatchException(BatchErrorCode errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
}
public enum BatchErrorCode {
PARTITION_ERROR("B001", "分批错误"),
TIMEOUT_ERROR("B002", "超时错误"),
RETRY_EXHAUSTED("B003", "重试耗尽"),
CIRCUIT_BREAKER("B004", "熔断器触发");
private final String code;
private final String description;
}
2 熔断器实现
@Component
public class CircuitBreaker {
private final Map<String, CircuitBreakerState> states = new ConcurrentHashMap<>();
@Value("${batch.circuit-breaker.threshold:10}")
private int failureThreshold;
@Value("${batch.circuit-breaker.timeout:60000}")
private long timeoutMs;
public boolean isOpen(String batchType) {
CircuitBreakerState state = states.get(batchType);
if (state == null) {
return false;
}
return state.isOpen();
}
public void recordFailure(String batchType) {
states.computeIfAbsent(batchType, k -> new CircuitBreakerState())
.incrementFailure();
}
public void recordSuccess(String batchType) {
CircuitBreakerState state = states.get(batchType);
if (state != null) {
state.reset();
}
}
}
使用示例
1 业务层调用
@Service
@Slf4j
public class UserBatchService {
@Autowired
private BatchInvoker batchInvoker;
@Autowired
private CircuitBreaker circuitBreaker;
@Autowired
private UserClient userClient;
public BatchResult<UserInfo> batchQueryUsers(List<Long> userIds) {
// 检查熔断器
if (circuitBreaker.isOpen("user-batch-query")) {
log.warn("Circuit breaker is open for user batch query");
return BatchResult.builder()
.success(false)
.errors(Collections.singletonMap(-1, "服务暂时不可用"))
.totalCount(userIds.size())
.failCount(userIds.size())
.build();
}
try {
BatchConfig config = BatchConfig.builder()
.batchSize(50)
.timeout(3000)
.retryTimes(2)
.build();
BatchResult<UserInfo> result = batchInvoker.execute(
userIds,
batch -> userClient.batchQuery(batch),
config
);
// 记录结果
if (result.isSuccess()) {
circuitBreaker.recordSuccess("user-batch-query");
} else {
circuitBreaker.recordFailure("user-batch-query");
}
return result;
} catch (Exception e) {
circuitBreaker.recordFailure("user-batch-query");
log.error("Batch query users failed", e);
throw new BatchException(BatchErrorCode.RETRY_EXHAUSTED, "批量查询用户失败");
}
}
}
2 测试代码
@SpringBootTest
class UserBatchServiceTest {
@Autowired
private UserBatchService userBatchService;
@Test
void testBatchQuery() {
List<Long> userIds = IntStream.rangeClosed(1, 100)
.mapToObj(Long::valueOf)
.collect(Collectors.toList());
BatchResult<UserInfo> result = userBatchService.batchQueryUsers(userIds);
assertThat(result.isSuccess()).isTrue();
assertThat(result.getSuccessCount()).isEqualTo(100);
assertThat(result.getCostTime()).isLessThan(5000);
}
}
最佳实践清单
✅ 必须遵循的规范
- 统一接口:所有批量处理使用统一接口
- 参数校验:必须校验批量大小、参数有效性
- 超时控制:设置合理的超时时间
- 异常处理:区分业务异常和系统异常
- 结果封装:返回统一的批量结果对象
⚠️ 需要避免的问题
- 无限增长:防止批处理数据量过大
- 资源泄露:确保线程池正确关闭
- 超时阻塞:避免长时间等待
- 错误忽略:不能静默处理异常
📊 配置建议
- 批量大小:20-100条
- 超时时间:3-5秒
- 重试次数:2-3次
- 熔断阈值:10次失败
这个规范确保了批量调用的可靠性、可监控性和可维护性。