Java批量调用流程如何规范

wen java案例 38

本文目录导读:

Java批量调用流程如何规范

  1. 核心设计原则
  2. 完整实现示例
  3. 配置管理规范
  4. 异常处理规范
  5. 使用示例
  6. 最佳实践清单

我来详细说明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);
    }
}

最佳实践清单

✅ 必须遵循的规范

  1. 统一接口:所有批量处理使用统一接口
  2. 参数校验:必须校验批量大小、参数有效性
  3. 超时控制:设置合理的超时时间
  4. 异常处理:区分业务异常和系统异常
  5. 结果封装:返回统一的批量结果对象

⚠️ 需要避免的问题

  1. 无限增长:防止批处理数据量过大
  2. 资源泄露:确保线程池正确关闭
  3. 超时阻塞:避免长时间等待
  4. 错误忽略:不能静默处理异常

📊 配置建议

  • 批量大小:20-100条
  • 超时时间:3-5秒
  • 重试次数:2-3次
  • 熔断阈值:10次失败

这个规范确保了批量调用的可靠性、可监控性和可维护性。

抱歉,评论功能暂时关闭!