本文目录导读:

我来详细说明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次失败
这个规范确保了批量调用的可靠性、可监控性和可维护性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播