Spring批处理:组装作业而不是配置作业(可扩展作业配置)
背景 我正在设计一个文件读取层,可以读取分隔文件并将其加载到Spring批处理:组装作业而不是配置作业(可扩展作业配置),spring,file,annotations,spring-batch,Spring,File,Annotations,Spring Batch,背景 我正在设计一个文件读取层,可以读取分隔文件并将其加载到列表中。我决定使用SpringBatch,因为它提供了许多可伸缩性选项,我可以根据文件的大小利用这些选项来处理不同的文件集 要求 我想设计一个通用的作业API,可以用来读取任何分隔文件 应该有一个作业结构,用于解析每个分隔文件。例如,如果系统需要读取5个文件,则将有5个作业(每个文件一个作业)。这5个作业彼此不同的唯一方式是,它们将使用不同的FieldSetMapper、列名、目录路径和其他缩放参数,如commit interval和t
列表中。我决定使用SpringBatch,因为它提供了许多可伸缩性选项,我可以根据文件的大小利用这些选项来处理不同的文件集
要求
我想设计一个通用的作业API,可以用来读取任何分隔文件
应该有一个作业结构,用于解析每个分隔文件。例如,如果系统需要读取5个文件,则将有5个作业(每个文件一个作业)。这5个作业彼此不同的唯一方式是,它们将使用不同的FieldSetMapper
、列名、目录路径和其他缩放参数,如commit interval
和throttle limit
李>
此API的用户不需要配置Spring
在系统中引入新的文件类型时,可以自行批处理作业、步骤、分块、分区等
用户需要做的只是提供作业使用的字段集映射器
,以及提交间隔
、限制
和放置每种类型文件的目录
每个文件将有一个预定义的目录。每个目录可以包含多个相同类型和格式的文件。将使用MultiResourcePartioner
查看目录内部。分区数=目录中的文件数
我的要求是构建一个Spring批处理基础设施,它为我提供了一个独特的工作,一旦我有了组成该工作的各个部分,我就可以启动它
我的解决方案:
我创建了一个抽象配置类,该类将由具体配置类扩展(每个要读取的文件将有一个具体类)
假设我还有一个名为Inventory
的类,它扩展了AbstractFileLoader。
在应用程序启动时,我可以按如下方式加载这两种注释配置:
AbstractApplicationContext context1 = new AnnotationConfigApplicationContext(InvoiceLoader.class, InventoryLoader.class);
在我的应用程序的其他地方,两个不同的线程可以启动作业,如下所示:
AbstractApplicationContext context1 = new AnnotationConfigApplicationContext(InvoiceLoader.class, InventoryLoader.class);
线程1:
JobLauncher jobLauncher1 = context1.getBean(JobLauncher.class);
Job job1 = context1.getBean("invoiceJob", Job.class);
JobExecution jobExecution = jobLauncher1.run(job1, jobParams1);
线程2:
JobLauncher jobLauncher1 = context1.getBean(JobLauncher.class);
Job job1 = context1.getBean("inventoryJob", Job.class);
JobExecution jobExecution = jobLauncher1.run(job1, jobParams1);
这种方法的优点是,每当有一个新文件要读取时,开发人员/用户所要做的就是创建子类AbstractFileLoader
,实现所需的抽象方法,而无需深入了解如何组装作业的细节
问题:
我是SpringBatch的新手,所以我可能忽略了这种方法中一些不太明显的问题,例如SpringBatch中的共享内部对象可能导致两个一起运行的作业失败,或者一些明显的问题,例如bean的作用域
有没有更好的方法来实现我的目标
@Value(#{stepExecutionContext['fileName']})的fileName
属性
始终被分配值为I:/CK/invoices/partitions/
,这是InvoiceLoader
中的getPath
方法返回的值,即使InventoryLoader`中的getPath方法返回不同的值
一个选项是将它们作为作业参数传递。例如:
@Bean
Job job() {
jobs.get("myJob").start(step1(null)).build()
}
@Bean
@JobScope
Step step1(@Value('#{jobParameters["commitInterval"]}') commitInterval) {
steps.get('step1')
.chunk((int) commitInterval)
.reader(new IterableItemReader(iterable: [1, 2, 3, 4], name: 'foo'))
.writer(writer(null))
.build()
}
@Bean
@JobScope
ItemWriter writer(@Value('#{jobParameters["writerClass"]}') writerClass) {
applicationContext.classLoader.loadClass(writerClass).newInstance()
}
使用MyWriter的
class MyWriter implements ItemWriter<Integer> {
@Override
void write(List<? extends Integer> items) throws Exception {
println "Write $items"
}
}
输出为:
INFO: Executing step: [step1]
Write [1, 2, 3]
Write [4]
Feb 24, 2016 2:30:22 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [SimpleJob: [name=myJob]] completed with the following parameters: [{commitInterval=3, writerClass=MyWriter}] and the following status: [COMPLETED]
Status is: COMPLETED, job execution id 0
#1 step1 COMPLETED
信息:执行步骤:[步骤1]
写[1,2,3]
写[4]
2016年2月24日下午2:30:22 org.springframework.batch.core.launch.support.simplejoblancher$1运行
信息:作业:[SimpleJob:[name=myJob]]已完成,并具有以下参数:[{CommitterServal=3,writerClass=MyWriter}],以下状态:[completed]
状态为:已完成,作业执行id为0
#1第1步完成
完整示例。这里的问题在哪里?如果我不清楚,很抱歉。问题在最后两段。我想在移动中组装一个新的作业
,而不是启动一个预先配置的作业。开发人员将提供FieldSetMapper
的子类和ItemWriter
以及其他参数,如提交间隔到我的FileLoader
。然后,FileLoader
应将这些组件组装成一个作业
,并启动作业
。我想代表开发人员组装作业,而不是要求他们配置作业。我的文章中的第1点和第2点详细说明了要求。编辑我的文章,使其清晰!那么您希望“用户”为FieldSetMapper
、ItemWriter
等提供bean?@artifact没错。我希望用户只提供FieldSetMapper
和ItemWriter
以及我文章中提到的其他参数。我将获取这些组件并组装一个作业
,然后启动它。因此,这里没有预先配置的作业。我必须从提供的组件中组装一个,然后启动它。此外,在应用程序的生命周期内,可能会多次调用此方法,因此每个作业都必须是唯一的,但我应该能够重用组件,例如JobLauncher
。坦白地说,我不知道如何实现这一点。@事实上,组装作业而不是要求“用户”配置作业的原因是,“用户”大多是支持人员,他们了解一些Java代码,能够编写简单的Java类,如FieldSetMapper
实现。要求他们配置Spring批处理
作业是毫无疑问的。这是有道理的。但是仍然存在重用这些代码来创建多个作业的问题。如果我想启动5个具有相同配置的作业,我将如何在不接触您的配置类的情况下启动它们。@CKK您是指5个作业实例还是5个不同的作业?在这个场景中,只有一个作业。如果你想要几份类似的工作,哟
def jobExecution = launcher.run(ctx.getBean(Job), new JobParameters([
commitInterval: new JobParameter(3),
writerClass: new JobParameter('MyWriter'), ]))
INFO: Executing step: [step1]
Write [1, 2, 3]
Write [4]
Feb 24, 2016 2:30:22 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO: Job: [SimpleJob: [name=myJob]] completed with the following parameters: [{commitInterval=3, writerClass=MyWriter}] and the following status: [COMPLETED]
Status is: COMPLETED, job execution id 0
#1 step1 COMPLETED