Spring 批处理:JobScope 在 Spring 3.0.0 中不可用
Spring batch : JobScope not available in Spring 3.0.0
根据 Spring 批次 documentation,JobScope
作为 Spring 批次 3.0 的一部分引入。但是,看起来 JobScope 注释在 Spring batch 3.0 jar 中不可用。我在 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 batch 3.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's 建议,我使用 @Scope(value = "job", proxyMode = ScopedProxyMode.TARGET_CLASS)
而不是 JobScope
注释,但 运行 进入以下异常:
java.lang.IllegalStateException: No Scope registered for scope name 'job'' exception
我尝试通过将以下 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 批处理 3.0.1 完美配合。
I am using annotation based configuration to write batch jobs. I need
the JobScope annotation for late-binding of job parameters to my
beans. Is there a way to do this without using JobScope?
它应该在没有 Jobscope 的情况下工作,通过使用 Stepscope 您可以访问作业参数,请参阅 https://docs.spring.io/spring-batch/reference/html/configureStep.html#step-scope
如果您需要所有 bean 的可用信息,您可以实现一个简单的 spring bean(并发哈希图类型)来保存信息
如果您需要为每个批次 运行 保留信息,您可以实现一个 JobExecutionListener,其中 puts/pulls* JobExecutionContext 中的信息并填充(上述)简单 bean
*) 如果需要重启
根据 Spring 批次 documentation,JobScope
作为 Spring 批次 3.0 的一部分引入。但是,看起来 JobScope 注释在 Spring batch 3.0 jar 中不可用。我在 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 batch 3.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's 建议,我使用 @Scope(value = "job", proxyMode = ScopedProxyMode.TARGET_CLASS)
而不是 JobScope
注释,但 运行 进入以下异常:
java.lang.IllegalStateException: No Scope registered for scope name 'job'' exception
我尝试通过将以下 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 批处理 3.0.1 完美配合。
I am using annotation based configuration to write batch jobs. I need the JobScope annotation for late-binding of job parameters to my beans. Is there a way to do this without using JobScope?
它应该在没有 Jobscope 的情况下工作,通过使用 Stepscope 您可以访问作业参数,请参阅 https://docs.spring.io/spring-batch/reference/html/configureStep.html#step-scope
如果您需要所有 bean 的可用信息,您可以实现一个简单的 spring bean(并发哈希图类型)来保存信息
如果您需要为每个批次 运行 保留信息,您可以实现一个 JobExecutionListener,其中 puts/pulls* JobExecutionContext 中的信息并填充(上述)简单 bean
*) 如果需要重启