Spring Batch 使用@JobScope 中的步骤定义基于 Java 的条件流
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/35294496/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Batch define conditional flow java-based using steps in @JobScope
提问by Rainer Montag
I have a problem defining a java-based job configuration in Spring Batch containing a conditional flow using steps in @JobScope, i.e. injecting a job parameter into the step at job execution time.
我在 Spring Batch 中定义基于 Java 的作业配置时遇到问题,其中包含使用 @JobScope 中的步骤的条件流,即在作业执行时将作业参数注入到步骤中。
My Setup:
我的设置:
- Spring Batch 3.0.4
- Spring Batch Admin 2.0.0.M1 (providing jobRepository, transactionManager, jobScope, stepScopebeans during runtime)
- 春季批次 3.0.4
- Spring Batch Admin 2.0.0.M1(在运行时提供jobRepository、transactionManager、jobScope、stepScopebean)
Assuming I have a simple job containing two steps step1 and step2, then defining and executing the job configuration without conditional flow is working:
假设我有一个包含两个步骤 step1 和 step2 的简单作业,那么在没有条件流的情况下定义和执行作业配置是有效的:
@Configuration
public class SimpleJobConfiguration {
@Bean
@JobScope
Step1Tasklet step1Tasklet(@Value("#{jobParameters['condition']}") String condition) {
Step1Tasklet tasklet = new Step1Tasklet(condition);
return tasklet;
}
// reader, writer ommitted
@Bean
@JobScope
public Step step1(@Value("#{jobParameters['condition']}") String condition) {
TaskletStep step = stepBuilderFactory().get(STEP_NAME_1)
.tasklet(step1Tasklet(condition))
.build();
return step;
}
@Bean
@JobScope
public Step step2() {
TaskletStep step = stepBuilderFactory().get(STEP_NAME_2)
.<String, String>chunk(10)
.reader(reader(null))
.writer(writer())
.allowStartIfComplete(true)
.build();
return step;
}
@Bean
public Job simpleJob() {
Job job = jobBuilderFactory().get(JOB_NAME)
.start(step1(null))
.next(step2())
.build();
return job;
}
- When deploying the job configuration, Spring Batch is initializing my Job bean without any exceptions. It does not initialize my steps - which makes sense because they are in Scope "Job".
- When launching an execution for this job configuration, Spring Batch is initializing both steps, injecting the job parameters as expected.
- The job is executed as expected, first step1 then step2.
- 部署作业配置时,Spring Batch 正在初始化我的 Job bean,没有任何异常。它不会初始化我的步骤 - 这是有道理的,因为它们在范围“作业”中。
- 启动此作业配置的执行时,Spring Batch 会初始化这两个步骤,并按预期注入作业参数。
- 作业按预期执行,首先是 step1,然后是 step2。
Now I want to add a simple conditional logic for my Job:
现在我想为我的工作添加一个简单的条件逻辑:
"IF (step1.exitStatus == "OK") THEN execute step2 ELSE finish job"
"IF (step1.exitStatus == "OK") THEN 执行 step2 ELSE 完成作业"
To achieve that I have defined a decider bean (implements JobExecutionDecider) and modified my Job definition:
为了实现这一点,我定义了一个决策程序 bean(实现了 JobExecutionDecider)并修改了我的 Job 定义:
@Bean
public SimpleStepDecider decider() {
SimpleStepDecider decider = new SimpleStepDecider();
return decider;
}
@Bean
// DOES NOT WORK; NEEDS TO BE FIXED!
public Job simpleJob() {
Job job = jobBuilderFactory().get(JOB_NAME)
.start(step1(null))
.next(decider())
.on("OK")
.to(step2())
.end()
.build();
return job;
}
Using this I got the following exception during deployment(!) of the job configuration:
使用它,我在作业配置的部署(!)期间遇到以下异常:
14:28:07,299 ERROR batch.local-startStop-1 context.ContextLoader:331 - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'simpleJob' defined in com.foo.bar.SimpleJobConfiguration: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.core.Job]: Factory method 'simpleJob' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.step1': Scope 'job' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for job scope
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
...
at org.springframework.batch.core.configuration.support.GenericApplicationContextFactory$ResourceXmlApplicationContext.<init>(GenericApplicationContextFactory.java:161)
...
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.batch.core.Job]: Factory method 'simpleJob' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.step1': Scope 'job' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for job scope
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 39 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.step1': Scope 'job' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: No context holder available for job scope
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:352)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:187)
at com.sun.proxy.$Proxy33.getName(Unknown Source)
at org.springframework.batch.core.job.builder.FlowBuilder.createState(FlowBuilder.java:282)
at org.springframework.batch.core.job.builder.FlowBuilder.doStart(FlowBuilder.java:265)
at org.springframework.batch.core.job.builder.FlowBuilder.start(FlowBuilder.java:122)
at org.springframework.batch.core.job.builder.JobFlowBuilder.<init>(JobFlowBuilder.java:39)
at org.springframework.batch.core.job.builder.SimpleJobBuilder.next(SimpleJobBuilder.java:133)
at com.foo.bar.SimpleJobConfiguration.simpleJob(SimpleJobConfiguration.java:145)
... 40 more
Caused by: java.lang.IllegalStateException: No context holder available for job scope
at org.springframework.batch.core.scope.JobScope.getContext(JobScope.java:153)
at org.springframework.batch.core.scope.JobScope.get(JobScope.java:92)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:337)
... 60 more
I tried out:
我试过了:
- moving step beans to "normal" scope
- Using step execution listener instead of decider
- 将 step bean 移动到“正常”范围
- 使用步骤执行侦听器而不是决策器
But no luck at all...
但是一点运气都没有...
Funny enough, i was able to define the same job using xml-based configuration, and it works as expected (decider is using value of job parameter 'condition' as exit status code; I tested both "OK" and "NOTOK" and they work as expected):
有趣的是,我能够使用基于 xml 的配置定义相同的作业,并且它按预期工作(决策者使用作业参数“条件”的值作为退出状态代码;我测试了“OK”和“NOTOK”,它们按预期工作):
<bean id="reader" class="com.foo.bar.MyReader" scope="job">
</bean>
<bean id="writer" class="com.foo.bar.MyWriter" />
<bean id="decider" class="com.foo.bar.SimpleStepDecider" />
<bean id="step1Tasklet" class="com.foo.bar.Step1Tasklet" scope="job">
<constructor-arg value="#{jobParameters['condition']}" />
</bean>
<batch:job id="simpleJob" restartable="true">
<batch:step id="step1" next="decision" allow-start-if-complete="true">
<batch:tasklet ref="step1Tasklet" />
</batch:step>
<batch:decision id="decision" decider="decider">
<batch:end on="NOTOK" />
<batch:next on="OK" to="step2"/>
<batch:fail on="*"/>
</batch:decision>
<batch:step id="step2" allow-start-if-complete="true">
<batch:tasklet allow-start-if-complete="true">
<batch:chunk reader="reader" writer="writer" commit-interval="1000" />
</batch:tasklet>
</batch:step>
</batch:job>
Can anyone give me a hint how I to get my java configuration working, i.e. step beans are instanciated during job execution?
谁能给我一个提示,我如何让我的 java 配置工作,即在作业执行期间实例化 step bean?
回答by FGreg
It could be that your are running into BATCH-2229: Unable to use Job Scope beans in a multi-threaded or partitioned stepwhich is currently unresolved.
可能是您遇到了BATCH-2229:无法在当前未解决的多线程或分区步骤中使用作业范围 bean。
This was raised in response to accessing Job Scoped beans from partitioned and/or multi-threaded steps:
这是为了响应从分区和/或多线程步骤访问作业范围 bean 而提出的:
Access @JobScope bean in spring batch with partitioned step
使用分区步骤在 spring 批处理中访问 @JobScope bean
回答by Tao Li
I think the problem is "step1(null)", try to change like this:
我认为问题是“step1(null)”,试着改成这样:
public Job simpleJob(Step step1) {
Job job = jobBuilderFactory().get(JOB_NAME)
.start(step1)
.next(decider())
.on("OK")
.to(step2())
.end()
.build();
return job;}