You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Batch MultiResourcePartitioner如何按文件名设置资源处理顺序

问题根因
  • 原生MultiResourcePartitioner的partition方法内部使用HashMap存储分区元数据,HashMap不保证插入顺序,即使传入的Resource数组是有序的,最终生成的分区列表也会打乱顺序。
  • 你的现有代码存在调用顺序错误:先执行partitioner.partition(1)再调用setResources,相当于先基于空资源生成了分区,后续设置的资源列表完全没有生效,进一步导致处理顺序异常。
修复方案

方案1:自定义有序分区器(推荐)

直接继承MultiResourcePartitioner,重写partition方法,使用LinkedHashMap存储分区,完全保留资源数组的插入顺序:

public class OrderedMultiResourcePartitioner extends MultiResourcePartitioner {
    @Override
    public Map<String, ExecutionContext> partition(int gridSize) {
        Resource[] resources = getResources();
        // 使用LinkedHashMap保留插入顺序
        Map<String, ExecutionContext> partitions = new LinkedHashMap<>();
        for (int i = 0; i < resources.length; i++) {
            ExecutionContext context = new ExecutionContext();
            context.put("fileName", resources[i].getFilename());
            context.put("file", resources[i]);
            partitions.put("partition-" + i, context);
        }
        return partitions;
    }
}

修改你的Bean定义,替换为自定义分区器,同时修正逻辑和调用顺序:

@Bean
@JobScope
public OrderedMultiResourcePartitioner paritioner() throws IOException {
    OrderedMultiResourcePartitioner partitioner = new OrderedMultiResourcePartitioner();
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();

    // 按你需要的逆序排序文件,直接生成有序的Resource数组即可,不需要HashMap中转
    Resource[] resources = listFiles.stream()
            .sorted(Comparator.reverseOrder())
            .map(path -> resolver.getResource("file:" + path))
            .toArray(Resource[]::new);

    // 不需要手动调用partition方法,Spring Batch执行时会自动调用
    partitioner.setResources(resources);
    return partitioner;
}

方案2:配置分区比较器

如果不想自定义分区器,可以在配置分区Step时,给PartitionHandler设置自定义分区排序器,按照分区名的后缀数字排序即可保证顺序和传入的资源数组一致:

@Bean
public TaskExecutorPartitionHandler partitionHandler(TaskExecutor taskExecutor, Step slaveStep) {
    TaskExecutorPartitionHandler handler = new TaskExecutorPartitionHandler();
    handler.setTaskExecutor(taskExecutor);
    handler.setStep(slaveStep);
    handler.setGridSize(listFiles.size());
    // 设置分区比较器,按分区序号升序处理
    handler.setPartitionComparator(Comparator.comparingInt(partitionName -> 
            Integer.parseInt(partitionName.split("-")[1])
    ));
    return handler;
}

内容的提问来源于stack exchange,提问作者Houssem MAAMRIA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 00:06:00