這里我們講述一下springbatch中關於step層面上面的數據共享技術。而對街的人影都浸染在一片薄荷的白色中,由於無聲,都好像經過漂染,不沾人間煙火。
step的數據共享
關於springbatch里面的step的數據共享,可以有很多的實現方式。比如可以用數據庫記載共享的數據、文件保存共享的數據等等。這里我們重點討論的是springbatch與spring可以解決這類問題的方案。總的來說,可以有如下兩種方式。
Execution context Use a Spring Batch execution context as a container for user data. A step writes to the execution context; then another step reads from the execution context. Holder Use a Spring bean and dependency injection. Spring injects a holder bean in the communicating beans. A first step sets values in the holder; another step reads values from the holder.
下面我們針對這同種方式做一個測試的案例。
一、使用Execution context方式共享數據
- 定義一個job,在batch.xml里面
<job id="shareDataContextJob"> <step id="setDateStep" next="getDateStep"> <tasklet transaction-manager="transactionManager" ref="setDataContextTasklet"/> </step> <step id="getDateStep"> <tasklet transaction-manager="transactionManager" ref="getDataContextTasklet"/> </step> </job>
- setDataContextTasklet與getDataContextTasklet的定義
<bean id="setDataContextTasklet" class="spring.batch.shareDataContext.SetDataContextTasklet"/> <bean id="getDataContextTasklet" class="spring.batch.shareDataContext.GetDataContextTasklet"/>
- setDataContextTasklet與getDataContextTasklet的實現
存放數據的實現類
package spring.batch.shareDataContext; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.repeat.RepeatStatus; /** * @Author: huhx * @Date: 2017-11-02 下午 8:41 */ public class SetDataContextTasklet implements Tasklet { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { ExecutionContext jobExecutionContext = chunkContext.getStepContext(). getStepExecution(). getJobExecution(). getExecutionContext(); jobExecutionContext.putString("username", "huhx"); System.out.println("set data tasklet."); return RepeatStatus.FINISHED; } }
得到數據的實現類
package spring.batch.shareDataContext; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.repeat.RepeatStatus; /** * @Author: huhx * @Date: 2017-11-02 下午 8:41 */ public class GetDataContextTasklet implements Tasklet { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { ExecutionContext jobExecutionContext = chunkContext.getStepContext(). getStepExecution(). getJobExecution(). getExecutionContext(); String username = jobExecutionContext.getString("username"); System.out.println("username = " + username); return RepeatStatus.FINISHED; } }
運行的結果,setDateStep得到的getDateStep存放的數據。
set data tasklet. username = huhx
另外我們還有另外一種寫法。在基於上述的代碼做如下的修改:getDataContextTasklet和定義與實現。注意scope="step"是必須的。
<bean id="getDataContextTasklet" class="spring.batch.shareDataContext.GetDataContextTasklet" scope="step"> <property name="username" value="#{jobExecutionContext['username']}"/> </bean>
getDataContextTasklet的實現類,可以直接注入username得到setDataContextTasklet里面設置的username值。
package spring.batch.shareDataContext; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.item.ExecutionContext; import org.springframework.batch.repeat.RepeatStatus; /** * @Author: huhx * @Date: 2017-11-02 下午 8:41 */ public class GetDataContextTasklet implements Tasklet { private String username; public void setUsername(String username) { this.username = username; } @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println("username = " + username); return RepeatStatus.FINISHED; } }
二、通過Spring holder beans共享數據
- 定義一個job,在batch.xml中
<job id="shareDataHolderJob"> <step id="setDateHolderStep" next="getDateHolderStep"> <tasklet transaction-manager="transactionManager" ref="setDataHolderTasklet"/> </step> <step id="getDateHolderStep"> <tasklet transaction-manager="transactionManager" ref="getDataHolderTasklet"/> </step> </job>
- setDataHolderTasklet、getDataHolderTasklet以及共享數據Bean類的定義
<!--通過holder分享數據--> <bean id="importMetadata" class="spring.batch.shareDataHolder.ImportMetadataHolder"/>
<bean id="setDataHolderTasklet" class="spring.batch.shareDataHolder.SetDataHolderTasklet"> <property name="importMetadataHolder" ref="importMetadata"/> </bean> <bean id="getDataHolderTasklet" class="spring.batch.shareDataHolder.GetDataHolderTasklet"> <property name="importMetadataHolder" ref="importMetadata"/> </bean>
- 上述xml定義的bean類的實現
ImportMetadataHolder:共享數據Bean類。
package spring.batch.shareDataHolder; import spring.batch.readFile.People; /** * @Author: huhx * @Date: 2017-11-03 上午 8:56 */ public class ImportMetadataHolder { private People people; public People getPeople() { return people; } public void setPeople(People people) { this.people = people; } }
SetDataHolderTasklet:設置共享數據的實現類
package spring.batch.shareDataHolder; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; import spring.batch.readFile.People; import java.util.Date; /** * @Author: huhx * @Date: 2017-11-03 上午 9:00 */ public class SetDataHolderTasklet implements Tasklet { private ImportMetadataHolder importMetadataHolder; public void setImportMetadataHolder(ImportMetadataHolder importMetadataHolder) { this.importMetadataHolder = importMetadataHolder; } @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { People people = new People(); people.setUsername("huhx"); people.setBirthday(new Date()); people.setAddress("武漢"); people.setAge(23); importMetadataHolder.setPeople(people); return RepeatStatus.FINISHED; } }
GetDataHolderTasklet:獲取共享數據的實現類
package spring.batch.shareDataHolder; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.scope.context.ChunkContext; import org.springframework.batch.core.step.tasklet.Tasklet; import org.springframework.batch.repeat.RepeatStatus; /** * @Author: huhx * @Date: 2017-11-03 上午 9:00 */ public class GetDataHolderTasklet implements Tasklet { private ImportMetadataHolder importMetadataHolder; public void setImportMetadataHolder(ImportMetadataHolder importMetadataHolder) { this.importMetadataHolder = importMetadataHolder; } @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { System.out.println(importMetadataHolder.getPeople()); return RepeatStatus.FINISHED; } }
運行的結果,在控制台打印:
username=huhx|age=23|address=武漢|birthday=Fri Nov 03 09:06:24 CST 2017
之所以ImportMetadataHolder類能夠共享,是由於spring中Bean的默認scope是singleton單例的。如果修改scope為prototype。那么輸出的結果為null。
另外這種方式也可以使用SpEL表達式的方式來注入要共享的數據。修改getDataHolderTasklet的定義和實現類以及修改importMetadata的scope=singleton。如下
<bean id="getDataHolderTasklet" class="spring.batch.shareDataHolder.GetDataHolderTasklet" scope="step"> <property name="username" value="#{importMetadata.getPeople().getUsername()}"/> </bean>
GetDataHolderTasklet可以直接注入username,打印它的結果為huhx。這里就不貼出代碼。
友情鏈接