2016-12-05 106 views
0

私は春のバッチジョブの下にあります。春のバッチ内のループのステップを実行する方法:更新を

<job id="MyBatchJob" job-repository="jobRepository"> 

    <step id="ConfigurationReadStep"> 
     <tasklet ref="ConfigurationReadTasklet" transaction-manager="jobRepository-transactionManager"/> 
     <next on="COMPLETED" to="NextStep" /> 
    </step>   

    <step id="NextStep"> 
    <tasklet transaction-manager="jobRepository-transactionManager"> 
     <chunk reader="myItemReader" writer="myItemWriter" commit-interval="1000"/> 
    </tasklet> 
    </step> 

    <listeners> 
     <listener ref="jobListener" /> 
    </listeners>  

</job> 

これは、いくつかのビジネスロジックの後、私が遭遇設定読み出しステップとして第一歩を持っていますクエリのリスト。例えば、たとえば10個のクエリ。私はJobExecutionContextPromotionListenerを使ってこのリストを宣伝できることを知っています。

はしかし、私は、これは読者のクエリとしての私の次のステップのリーダーに1で1を照会し、すべての読者の問い合わせが消費されるまで、ループ内でそのステップを実行餌にしたいです。膨大な数のアイテムを返す可能性があるため、これらのクエリをそれぞれ春バッチシナリオとして実行したいと思います。

どうすればいいですか?

***********************************更新********** ************************

これは私が何をしようとしていますものです:タスクレットで

<job id="MyJob" job-repository="jobRepository"> 

     <step id="ConfigurationReadStep"> 
      <tasklet ref="ConfigurationReadTasklet" transaction-manager="jobRepository-transactionManager"/> 
      <next on="COMPLETED" to="MyNextStep" />  
      <listeners> 
       <listener ref="promotionListener"/> 
      </listeners> 
     </step>   

    <step id="MyNextStep" next="limitDecision"> 
     <tasklet transaction-manager="jobRepository-transactionManager"> 
      <chunk reader="MyItemReader" writer="MyItemWriter" commit-interval="1000"/> 
     </tasklet> 
    </step> 

    <decision id="limitDecision" decider="limitDecider"> 
     <next on="CONTINUE" to="MyNextStep" /> 
     <end on="COMPLETED" /> 
    </decision> 

    <listeners> 
     <listener ref="jobListener" /> 
    </listeners> 

    </job> 

<beans:bean id="jobListener" class="com.hsbc.gbm.dml.integration.batch.listener.SimpleJobListener" /> 

<beans:bean id="promotionListener" class="org.springframework.batch.core.listener.ExecutionContextPromotionListener"> 
    <beans:property name="keys" value="readerLimit,readerQueries,readerSQL" /> 
</beans:bean> 

    <beans:bean id="ConfigurationReadTasklet" class="com.mypackage.ConfigurationReadTasklet" scope="step"> 
    </beans:bean> 

<beans:bean id="MyItemReader" class="org.springframework.batch.item.database.JdbcCursorItemReader" scope="step"> 
    <beans:property name="dataSource" ref="myDataSource" /> 
    <beans:property name="sql" value="#{jobExecutionContext['readerSQL']}" /> 
    <beans:property name="rowMapper"> 
     <beans:bean name="mapper" class="com.mypackage.MyRowMapper" /> 
    </beans:property> 
</beans:bean> 

<beans:bean id="MyItemWriter" class="com.mypackage.MyItemWriter" scope="step"> 
    <beans:constructor-arg ref="myDataSource" /> 
</beans:bean> 

<beans:bean id="limitDecider" class="com.mypackage.StepLoopLimitDecider" scope="step"> 
    <beans:property name="readerQueries" value="#{jobExecutionContext['readerQueries']}" /> 
</beans:bean>  

、私は意志リーダクエリのリストを取得する。最初にreaderQueryと設定し、次のステップに進みます。これは通常バネ一歩のステップとして実行されます。これが完了すると

が、私はより多くの読者の問い合わせがある場合は、はい、それは次のクエリにreaderQueryを変更し、再実行NextStepを場合、私Deciderは、確認したい、他のジョブが完了します。以下は私の決定者です

public class StepLoopLimitDecider implements JobExecutionDecider { 

private List<String> readerQueries; 

private int count = 1; 

public FlowExecutionStatus decide(JobExecution jobExecution,StepExecution stepExecution) { 
    if (count >= this.readerQueries.size()) { 
     return new FlowExecutionStatus("COMPLETED"); 
    } 
    else { 
     System.out.println(count + ": "+readerQueries.get(count)); 
     jobExecution.getExecutionContext().put("readerSQL", readerQueries.get(count)); 
     count = count + 1; 
     return new FlowExecutionStatus("CONTINUE"); 
    } 
} 

public void setReaderQueries(List<String> readerQueries) { 
    this.readerQueries = readerQueries; 
} 
} 

しかし、これは機能しません。ステップは初めて正しく実行されます。しかしDeciderは以下のエラーで失敗します:

2016-12-06 14:46:24 ERROR AbstractJob:306 - Encountered fatal error executing job 
org.springframework.batch.core.JobExecutionException: Flow execution ended unexpectedly 
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:141) 
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:281) 
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120) 
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:48) 
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:114) 
    at org.springframework.batch.core.launch.support.CommandLineJobRunner.start(CommandLineJobRunner.java:348) 
    at org.springframework.batch.core.launch.support.CommandLineJobRunner.main(CommandLineJobRunner.java:565) 
Caused by: 
org.springframework.batch.core.job.flow.FlowExecutionException: Ended flow=MyBatchJob at state=MyBatchJob.limitDecision with exception 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:152) 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124) 
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135) 
    ... 6 more 
Caused by: 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.limitDecider': 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:339) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:190) 
    at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:33) 
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:182) 
    at $Proxy4.decide(Unknown Source) 
    at org.springframework.batch.core.job.flow.support.state.DecisionState.handle(DecisionState.java:43) 
    at org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean$DelegateState.handle(SimpleFlowFactoryBean.java:141) 
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144) 
    ... 8 more 
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:325) 
    ... 15 more 

誰かがこの作業を手伝ってくれますか?

+0

がスコープステップすることができないので、決定はスプリングバッチ内のステップではありません。その仕事をスコープにして、物事は私が見ることができるはずです... –

答えて

1

私はあなたのクエリを計算し、ビジネス・ロジックの結果に基づいて動的にあなたの仕事を構築することを示唆しています。

しかし、あなたはXML-設定でこれを行うcannnot、それゆえ、私は、Java-config設定APIを使用することを示唆しています。

私は「どのように動的にジョブを作成する」に類似した質問には、いくつかの答えを書かれています。もっと遠くのアドバイスが必要な場合は、それらを見て、私に知らせてください。

SpringBatch - javaconfig vs xml

Spring Batch Java Config: Skip step when exception and go to next steps

Spring batch repeat step ending up in never ending loop

Spring Batch - How to generate parallel steps based on params created in a previous step

Spring Batch - Looping a reader/processor/writer step

+0

ありがとう。私の質問で更新を確認してください。私はアプローチをしようとしているが動作していない。 – Nik

+0

これは動作しません。 SpringBatchは、単一のジョブの起動中に特定のステップを複数回実行することを意図していません。このフレームワークは、ステップとリーダとライタのいくつかの内部状態を保持します。実行時にインスタンス化されたジョブ構造をハックして、ステップとリーダとライターの状態を何らかの形でリセットする必要があります。しかし、それはとても醜いと汚れたハックです。間違いなくあなたがやりたいことではありません。 –

+0

私が説明しようとしたように、Java-APIに慣れてください。 XMLの代わりにJavaコードを使用してジョブを作成します。私が理解する限りでは、アプリケーションを起動した後に、作成する必要があるさまざまなステップを決定することができます。これはJava-Apiで行うことができます。ここで私の答えを見て:http://stackoverflow.com/questions/37238813/spring-batch-looping-a-reader-processor-writer-step/37271735#37271735 –

関連する問題