当前位置: 首页 > 知识库问答 >
问题:

Spring批处理:JobScope在Spring 3.0.0中不可用

段干博涉
2023-03-14

根据Spring batch文档,jobscope是作为Spring batch 3.0的一部分引入的。但是,看起来JobScope注释在Spring Batch3.0JAR中不可用。我在pom.xml中指定了spring-batch-core依赖项,如下所示:

<properties>
    <jdk.version>1.6</jdk.version>
    <spring.version>4.2.4.RELEASE</spring.version>
    <spring.batch.version>3.0.0.RELEASE</spring.batch.version>
</properties>

<dependencies>

    <!-- Spring Batch dependencies -->
    <dependency>
        <groupId>org.springframework.batch</groupId>
        <artifactId>spring-batch-core</artifactId>
        <version>${spring.batch.version}</version>
    </dependency>

当我将spring-batch-version更改为3.0.6时,jobscope注释会按预期找到。我的理解是jobscope是作为spring Batch3.0的一部分引入的,因此应该可以在从3.0.0开始的任何spring batch jar中使用。

为什么jobscope注释在3.0.0版中不可用,或者我需要手动添加包含此注释的附加JAR吗?我相信spring-batch-core依赖项应该拉出所有附加的spring批处理依赖项,我不需要显式地指定它们。

我正在使用基于注释的配置来编写批处理作业。我需要jobscope注释来后期将作业参数绑定到bean。有没有一种不使用jobscope的方法可以做到这一点?

编辑

我的作业配置文件如下:

@Configuration
@EnableBatchProcessing
public class FileLoaderConfigurationNoAbstractLoader {

    @Autowired
    private ResourcePatternResolver resourcePatternResolver;

    @Bean
    public Job job(JobBuilderFactory jobs, Step s1) {
        return jobs.get("FileLoader").incrementer(new RunIdIncrementer()).start(s1).build();
    }

    @Bean
    @StepScope
    @SuppressWarnings("rawtypes")
    public FlatFileItemReader reader(@Value("#{stepExecutionContext['fileName']}") String filePath,
            @Value("#{jobParameters['fieldSetMapperClass']}") String fieldSetMapperClass,
            @Value("#{jobParameters['processType']}") String processType, @Value("#{jobParameters['dataType']}") String dataType,
            FileLoaderCreator loader) {
        String path = filePath.substring(filePath.indexOf(":") + 1, filePath.length());
        return loader.getReader(path, fieldSetMapperClass, processType, dataType);
    }

    @Bean
    @Scope(value = "job", proxyMode = ScopedProxyMode.TARGET_CLASS)
    @SuppressWarnings("rawtypes")
    public ItemWriter writer(@Value("#{jobParameters['dataType']}") String dataType) {
        return new CollectionItemWriter(dataType);
    }

    @Bean
    @Scope(value = "job", proxyMode = ScopedProxyMode.TARGET_CLASS)
    @SuppressWarnings("rawtypes")
    public ItemProcessor processor(FileLoaderCreator loader, @Value("#{jobParameters['itemProcessorClass']}") String itemProcessorClass) {
        return loader.getItemProcessor(itemProcessorClass);
    }

    @Bean
    @Scope(value = "job", proxyMode = ScopedProxyMode.TARGET_CLASS)
    @SuppressWarnings("all")
    public Step readStep(StepBuilderFactory stepBuilderFactory, ItemReader reader, ItemWriter writer, ItemProcessor processor,
            TaskExecutor taskExecutor, FileLoaderCreator fileLoader, @Value("#{jobParameters['dataType']}") String dataType,
            @Value("#{jobParameters['processType']}") String processType) {

        final Step readerStep = stepBuilderFactory.get(dataType + " ReadStep:slave")
                .chunk(fileLoader.getCommitInterval(processType, dataType)).reader(reader).processor(processor).writer(writer)
                .taskExecutor(taskExecutor).throttleLimit(fileLoader.getThrottleLimit(processType, dataType)).build();

        final Step partitionedStep = stepBuilderFactory.get(dataType + " ReadStep:master").partitioner(readerStep)
                .partitioner(dataType + " ReadStep:slave", partitioner(fileLoader, null, null)).taskExecutor(taskExecutor).build();

        return partitionedStep;

    }

    @Bean
    @Scope(value = "job", proxyMode = ScopedProxyMode.TARGET_CLASS)
    public Partitioner partitioner(FileLoaderCreator fileLoader, @Value("#{jobParameters['processType']}") String processType,
            @Value("#{jobParameters['dataType']}") String dataType) {
        MultiResourcePartitioner partitioner = new MultiResourcePartitioner();
        Resource[] resources;
        try {
            resources = resourcePatternResolver.getResources("file:" + fileLoader.getPath(processType, dataType)
                    + fileLoader.getFilePattern(processType, dataType));
        } catch (IOException e) {
            throw new RuntimeException("I/O problems when resolving the input file pattern.", e);
        }
        partitioner.setResources(resources);
        return partitioner;
    }

    /*
     * Use this if you want the writer to have job scope (JIRA BATCH-2269).
     * Might also change the return type of writer to ListItemWriter for this to
     * work.
     */
    @SuppressWarnings("serial")
    @Bean
    public TaskExecutor taskExecutor() {
        return new SimpleAsyncTaskExecutor() {
            @Override
            protected void doExecute(final Runnable task) {
                // gets the jobExecution of the configuration thread
                final JobExecution jobExecution = JobSynchronizationManager.getContext().getJobExecution();
                super.doExecute(new Runnable() {
                    public void run() {
                        JobSynchronizationManager.register(jobExecution);

                        try {
                            task.run();
                        } finally {
                            JobSynchronizationManager.close();
                        }
                    }
                });
            }
        };
    }

    @Bean
    public FileLoaderCreator loader() {
        System.out.println("Creating loader only once ");
        return new FileLoaderCreator();
    }

    @Bean
    public JobResults jobResults() {
        return new JobResults();
    }
}

根据M.Deinum的建议,我使用了@scope(value=“job”,proxyMode=scopedproxymode.target_class)而不是jobscope注释,但遇到了以下异常:

java.lang.IllegalStateException:没有为作用域名称“job”注册作用域异常

我尝试通过在上面的配置中添加以下bean来修复这个问题:

    @Bean
    public JobScope jobScope() {
        JobScope scope = new JobScope();
        scope.setAutoProxy(false);
        return scope;
    }

这在我的java配置中的以下一行给出了一个异常:

resources = resourcePatternResolver.getResources("file:" + fileLoader.getPath(processType, dataType)
                + fileLoader.getFilePattern(processType, dataType));

请注意,这在jobscope和spring batch 3.0.1中非常适用。

共有1个答案

公德明
2023-03-14

我正在使用基于注释的配置来编写批处理作业。我需要JobScope注释来后期将作业参数绑定到bean。有没有一种不使用JobScope就能做到这一点的方法?

它应该在没有Jobscope的情况下工作,通过使用Stepscope您可以访问jobparameters,请参阅https://docs.spring.io/spring-batch/reference/html/configurestep.html#step-scope

如果需要所有bean可用的信息,可以实现一个简单的spring bean(类型为concurrent hashmap)来保存信息

如果需要为每次批处理运行保留信息,可以实现JobExecutionListener,它将JobExecutionContext中的信息puts/puls*并填充(前面提到的)简单bean

*)如果需要重新启动

 类似资料:
  • 是否有方法访问分区步骤中定义为JobScope的bean? 我们将http客户端bean定义为JobScope,因为每个作业都是唯一的,但它是动态创建的,我们需要在从属步骤中使用它来发出post请求。当我们自动连线我们得到的一切 这里是作业配置类(我删除了所有不需要的内容,只剩下分区步骤和客户机类的配置,它们位于作业范围中,因为在每次作业运行时都需要特定于作业: 下面是CaptureerStock

  • 需要读取spring批处理中的文件,对其进行处理并将其作为一个提要保存。一个提要包含50%的信息。当我必须持久化提要的最终结果时,我需要使用公共字段将它们组合起来,并像一个项目一样持久化。请参见下面的示例。 我需要保留的最终信息如下: 请建议我如何在我的Spring批工作中实现这一点。 谢谢

  • 我正在使用spring批处理使用RepositoryItemReader从postgresql DB读取记录,然后将其写入主题。我看到大约有100万条记录需要处理,但它并没有处理所有的记录。我已经将reader的pageSize设置为10,000并且与提交间隔(块大小)相同

  • 我有以下工作要处理在一定的时间间隔或特别的基础上。 作业中的步骤如下: 我也想要用户界面,在那里我可以触发一个特别的基础上的工作,而且我应该能够提供参数从用户界面。 我想用Spring batch来完成这个任务,但它更多的是用于读->处理->写之类的工作。这里,在第一步中,我正在生成由第二步读取的数据。我不确定我是否还可以使用Spring batch来实现这个,或者有更好的方法来实现这个。

  • 我是Spring批处理的新手,我只想问如何从多行结果集中检索数据。我有以下场景: > 有两个不同的表说员工 使用时,我只能创建一个工资单子级,但该表可能有多个子级。请帮助...

  • 当我使用Spring批处理管理运行长时间运行的批处理作业的多个实例时,它会在达到jobLauncher线程池任务执行程序池大小后阻止其他作业运行。但是从cron中提取多个工作似乎效果不错。下面是作业启动器配置。 Spring批处理管理员Restful API是否使用不同于xml配置中指定的作业启动器?