通用的 Provider-Composer 异步编排模式 Spring Boot Starter。
将多数据源异步聚合查询的编排逻辑封装为开箱即用的组件,支持按优先级分阶段并行执行、结果统一组装。
<dependency>
<groupId>com.dolbyhub</groupId>
<artifactId>provider-composer-spring-boot-starter</artifactId>
<version>1.0.0</version>
</dependency>每个 Provider 负责从一个数据源获取数据:
@Component
public class UserBasicInfoProvider implements DataProvider<String, UserInfo> {
@Override
public String getName() {
return "user-basic";
}
@Override
public int getOrder() {
return 10; // 同 order 并行,不同 order 串行
}
@Override
public UserInfo apply(String userId) {
return userService.getBasicInfo(userId);
}
}
@Component
public class UserOrderProvider implements DataProvider<String, List<Order>> {
@Override
public String getName() {
return "user-orders";
}
@Override
public int getOrder() {
return 10; // 与 UserBasicInfoProvider 同一批并行执行
}
@Override
public List<Order> apply(String userId) {
return orderService.getOrders(userId);
}
}
@Component
public class UserCreditProvider implements DataProvider<String, CreditInfo> {
@Override
public String getName() {
return "user-credit";
}
@Override
public int getOrder() {
return 20; // 等第一批完成后再执行
}
@Override
public CreditInfo apply(String userId) {
return creditService.getCreditInfo(userId);
}
}@Component
public class UserResultComposer implements ResultComposer<UserProfileResponse> {
@Override
public UserProfileResponse compose(Map<String, Object> source) {
UserProfileResponse response = new UserProfileResponse();
response.setBasicInfo((UserInfo) source.get("user-basic"));
response.setOrders((List<Order>) source.get("user-orders"));
response.setCreditInfo((CreditInfo) source.get("user-credit"));
return response;
}
}方式一:使用 ProviderExecutorFactory
@Service
public class UserQueryService {
private final ProviderExecutorService<String> executor;
private final UserResultComposer composer;
public UserQueryService(ProviderExecutorFactory factory,
ApplicationContext context,
UserResultComposer composer) {
this.executor = factory.create(context, DataProvider.class);
this.composer = composer;
}
public UserProfileResponse queryUser(String userId)
throws ExecutionException, InterruptedException {
return executor.executeAndCompose(userId, composer);
}
}方式二:手动创建 ProviderExecutorService
@Service
public class UserQueryService {
private final ProviderExecutorService<String> executor;
public UserQueryService(ApplicationContext context,
@Qualifier("providerComposerExecutor") Executor exec) {
Collection<DataProvider> providers = context.getBeansOfType(DataProvider.class).values();
this.executor = new ProviderExecutorService<>(providers, exec);
}
public Map<String, Object> queryUser(String userId)
throws ExecutionException, InterruptedException {
return executor.executeAsync(userId);
}
}ops:
provider-composer:
enabled: true
core-pool-size: 10
max-pool-size: 20
queue-capacity: 200
thread-name-prefix: biz-provider-
keep-alive-seconds: 120通过 getOrder() 控制执行顺序:
| order 值 | 行为 |
|---|---|
| 相同 | 同一批次 并行执行(CompletableFuture.allOf) |
| 不同 | 按 order 从小到大 串行分批执行 |
| 默认 (MAX_VALUE) | 所有未指定 order 的 Provider 合并到同一批并行执行 |
示例:假设有 5 个 Provider,order 分别为 10, 10, 10, 20, 30
Batch 0 (order=10): [A, B, C] → 并行执行,allOf().get() 等待
Batch 1 (order=20): [D] → 串行执行,allOf().get() 等待
Batch 2 (order=30): [E] → 串行执行,allOf().get() 等待
