Spring Batch:在处理器中获取分区步骤的步骤上下文

时间:2013-05-15 18:45:28

标签: spring-batch

我正在开发一个Spring Batch作业,它使用MultiResourcePartitioner并行处理多个输入文件。在ItemProcessor中,我需要获取当前输入文件中的记录数。我从步骤上下文中获取当前文件名,并读取文件中的行数:

StepSynchronizationManager.register(stepExecution);
StepContext stepContext = StepSynchronizationManager.getContext();
StepSynchronizationManager.close();
log.trace("stepContext: " + stepContext.getStepExecution().getExecutionContext().entrySet().toString());
...
UrlResource currentFile = new UrlResource(stepContext.getStepExecution().getExecutionContext().getString("fileName"));

这一切似乎都有效但我从处理器线程访问步骤上下文时遇到异常:

2013-05-15 11:44:35,178 DEBUG [org.springframework.batch.core.step.tasklet.TaskletStep] <taskExecutor-3> - Rollback for RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.processor': Scope 'step' 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 step scope
2013-05-15 11:44:35,194 DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] <taskExecutor-3> - Returning JDBC Connection to DataSource
2013-05-15 11:44:35,194 DEBUG [org.springframework.batch.repeat.support.RepeatTemplate] <taskExecutor-3> - Handling exception: org.springframework.beans.factory.BeanCreationException, caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.processor': Scope 'step' 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 step scope
2013-05-15 11:44:35,194 DEBUG [org.springframework.batch.repeat.support.RepeatTemplate] <taskExecutor-3> - Handling fatal exception explicitly (rethrowing first of 1): org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.processor': Scope 'step' 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 step scope
2013-05-15 11:44:35,210 ERROR [org.springframework.batch.core.step.AbstractStep] <taskExecutor-3> - Encountered an error executing the step
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.processor': Scope 'step' 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 step scope
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:341)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:192)
    at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:33)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:182)
    at $Proxy14.process(Unknown Source)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.doProcess(SimpleChunkProcessor.java:125)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.transform(SimpleChunkProcessor.java:291)
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:190)
    at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:74)
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:386)
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130)
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:264)
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76)
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367)
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214)
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143)
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:250)
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195)
    at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:120)
    at org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler$1.call(TaskExecutorPartitionHandler.java:118)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.IllegalStateException: No context holder available for step scope
    at org.springframework.batch.core.scope.StepScope.getContext(StepScope.java:197)
    at org.springframework.batch.core.scope.StepScope.get(StepScope.java:139)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:327)
    ... 24 more

有没有办法从分区作业的处理器获取当前输入文件名?

以下是相关配置:

<batch:job id="acct">
    <batch:step id="init" parent="abstractStep" next="processStep">
        <batch:tasklet ref="fileDeleteTasklet" />
    </batch:step>
    <batch:step id="processStep">
        <batch:partition step="processInput" partitioner="partitioner">
            <batch:handler grid-size="2" task-executor="taskExecutor" />
        </batch:partition>
    </batch:step>
</batch:job>

<batch:step id="processInput">
    <batch:tasklet>
        <batch:chunk reader="reader" processor="processor" writer="writer" commit-interval="3">
            <batch:streams>
                <batch:stream ref="reader"/>
                <batch:stream ref="flatFileItemWriter"/>
            </batch:streams>
        </batch:chunk>
    </batch:tasklet>
</batch:step>

<bean id="partitioner" class="org.springframework.batch.core.partition.support.MultiResourcePartitioner" scope="step">
    <property name="keyName" value="fileName"/>
    <property name="resources" value="file:#{jobParameters['inputFilePattern']}"/>
</bean>

<bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="5"/>
    <property name="maxPoolSize" value="5"/>
</bean>

<bean id="reader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
    <property name="resource" value="#{stepExecutionContext[fileName]}" /> 
    <property name="lineMapper">
        <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
            <property name="lineTokenizer">
                <bean class="org.springframework.batch.item.file.transform.FixedLengthTokenizer">
                    <property name="names" value="recordType,reserved,aCode,bCode,acctNumber,idType,cCode" />
                    <property name="columns" value="1,2,3-6,7-9,10-15,16,17-19" />
                    <property name="strict" value="false" />
                </bean>
            </property>
            <property name="fieldSetMapper">
                <bean class="com.example.batch.acct.AcctInputFieldSetMapper" />
            </property>
        </bean>
    </property>
</bean>

<bean id="processor" class="com.example.batch.acct.AcctProcessor" scope="step">
    <property name="soapClient"  ref="soapClient" />
    <property name="maxNumIds"   value="${batch.soap.numberOfIds}" />
    <aop:scoped-proxy />
</bean>

2 个答案:

答案 0 :(得分:1)

回答Spring Batch forum

  

ItemProcessor接口没有公开访问的方法   StepContext,所以你需要自己注射它:

<bean id="itemProcessor" class="com.myApp.MyItemProcessor" scope="step">
    <property name="stepContext" value="#{stepExecutionContext}"/>
</bean>
     

假设您的处理器类具有名为的公开属性   stepContext

     

- Michael MinellaSpring Batch Lead

答案 1 :(得分:0)

<bean id="itemProcessor" class="com.myApp.MyItemProcessor" scope="step">
    <property name="stepContext" value="#{stepExecutionContext}"/>
</bean>

在这种情况下stepContexorg.springframework.batch.core.scope.context.StepContext的类型,如何建议此属性的名称,我将获得例外:

  

org.springframework.beans.factory.BeanCreationException:错误   用名字创建bean   'scopedTarget.itemProcessor'中的定义   类路径资源[META-INF / jobs / Job.xml]:   bean的初始化失败;嵌套异常是   org.springframework.beans.ConversionNotSupportedException:失败   转换类型'java.util.Collections $ UnmodifiableMap'的属性值   要求的类型   'org.springframework.batch.core.scope.context.StepContext'for   property'stepContext';嵌套异常是   java.lang.IllegalStateException:无法转换类型的值   'java.util.Collections $ UnmodifiableMap'到必需的类型   'org.springframework.batch.core.scope.context.StepContext'for   property'stepContext':没有匹配的编辑器或转换策略   结果

我需要访问jobExecutionId内的ItemProcessor,因此我将此配置更改为:

<bean id="itemProcessor" class="com.myApp.MyItemProcessor" scope="step">
    <property name="stepExecution" value="#{stepExecution}"/>
</bean>

属性"stepExecution"org.springframework.batch.core.StepExecution

类型