领先一步
VMware 提供培训和认证,助您加速前进。
了解更多我们一直在努力为 Spring Batch 准备 Spring 产品组合 2.5 发布列车,我认为现在是向大家更新情况的好时机。在本文中,我将稍微扩展一下领域建模,以及我们提升一些核心领域对象的地位并增加其职责的决定。我还会预览一下在接下来的几个版本中,直到 1.0 版本之前会推出的一些内容,以便大家有机会发表评论。
先道个歉:自从我上次撰写关于 Spring Batch 的博客以来,其内部发生了一些相当重要的变化,所以我感觉自己疏忽了。在本文中,我认为无法涵盖所有变化,但我保证将来会努力更及时地更新,并且随着 1.0 版本临近,我一定会让大家了解最新情况。(注意:Spring 产品组合 2.5 发布列车包含 Spring Batch 1.0。)
由于自 1.0.0-m3 以来我们已经修复了 70 多个问题,我们觉得是时候发布一个新版本了。我们上周制定的计划是明天(2 月 5 日)发布 1.0.0-m4,范围比原计划略窄(例如,推迟 XML 命名空间的实现)。然后大约 10-14 天后发布 1.0.0-m5,并在 3 月 20 日最终发布 1.0.0 之前至少有一个发布候选版本的时间。
Spring Batch 核心是一个相当紧凑的 API。实际上,它几乎不包含我们期望批处理应用程序开发人员必须实现或扩展的内容,因此它实际上是一个内部 API。然而,它对 Spring Batch 用户产生了相当深远的影响,因为它塑造了我们思考批处理作业及其执行方式,以及(对用户更重要的)其实现、配置和部署方式。
直到 1.0.0-m3,我们的 API 与批处理的通用语言之间存在经典的失配。我们不得不一直解释说一个JobConfiguration是大多数人认为的“Job”(同样适用于StepConfiguration和“Step”)。“Job”是您配置每天运行的东西,但每次运行时,它都有一个新的身份。这清楚地表明“Job”是领域概念的名称,那我们为什么称它为“JobConfiguration”呢?问得好。所以现在(在 1.0.0-m4 中),用户配置的东西是一个Job,当它运行时,我们创建一个新的JobInstance。同样适用于Step和StepInstance。因此,实体(Entity)原型由*Instance对象来实现 - 它们具有 ID 和数据库中的主键。例如,可以是 [JobInstance2008 年 2 月 2 日生效],对于 ["end-of-day"(日终)Job].
] JobInstance。其他实体原型是JobExecution和StepExecution和。自 m3 以来,这些原型名称或职责没有改变。当一个JobInstanceJobInstance 执行时,我们创建一个JobExecutionJobExecution(首先确保该实例尚未执行)。此时,[JobExecutionJobExecution 在 2 月 2 日晚上 10 点],属于 [JobInstanceJobInstance 在 2008 年 2 月 2 日生效],用于 ["end-of-day"(日终)Job] Job,启动。但是如果它失败了,并且第二天重新启动,那么我们需要一个新的 [JobExecutionJobExecution 在 2 月 3 日晚上 10:12],用于同一个JobInstance(即 [JobInstanceJobInstance 在 2008 年 2 月 2 日生效],用于 ["end-of-day"(日终)JobJobInstance])。因此JobJobInstance 与JobInstanceJobExecution 是一对多关系,而 JobExecution 又与JobExecutionStepExecution 是一对多关系。同样适用于Step*.
我们还对 API 关于Job和StepStep 在 1.0.0-m4 中的执行方式进行了更改。直到 1.0.0-m3,我们对每种执行都有单独的接口 -JobExecutor执行JobJobConfiguration,而StepExecutor执行Step执行 StepConfiguration。正如我们在设计时所想的那样,这具有封装的好处 - 我们设想了多个StepExecutorJobExecutor 实现,都能够执行同一个StepJob。然而,在实践中,随着我们对实现轮廓了解得更多,我们发现这是一个人为的区分。有趣的是,这个迹象是我们在 Java 中的StepExecutorExecutor 实现中进行了过多的“instanceof”检查 - 它们总是需要针对不同的StepStep 实现做特殊处理。最终很明显,每个StepStep 都必须知道如何执行自己。就像所有这样的领悟一样,一旦看到了就显而易见,但在此之前却完全不是。感谢 Eric Evans。
所以,例如,StepStep 领域的核心接口是
public interface Step {
// ... properties that the Job needs to know here ...
void execute(StepExecution stepExecution)
throws StepInterruptedException, BatchCriticalException;
}
StepStepStep 接口不需要从其execute方法返回任何内容,因为传递进来的StepExecutionStepExecution 在步骤执行过程中会被更新。它由调用者传入,并且在需要时可以用来监控执行的进度。它还可以用来停止执行,如果调用者需要中断作业(因此有了StepInterruptedException),只需设置一个标志setTerminateOnly()。这是有人问过我的事情,所以可能值得在这里提一下:该StepStep 实现负责在可行的情况下检查该标志的值,因此框架中内置了一种机制来指示作业提前终止。设置该标志的效果取决于StepStep,但我们提供了一个SimpleStep,它会在处理每个项目后检查该标志,并在必要时中止。它还接受一个StepInterruptPolicy策略,可用于检查其他异常情况(例如,Thread.isInterrupted()).
Spring Batch 命名空间Spring Batch 几乎是 Spring XML 命名空间可以帮助应用程序开发人员简化事情的完美例子。我们尚未实现NamespaceHandler,但它计划在下一个里程碑 1.0.0-m5 中实现,所以现在是您看看示例感觉如何的好时机。
座右铭是“让配置看起来像领域模型”,本着这种精神,看看这个例子,看看它是否有意义。这是新命名空间的草案,它模仿了现有的固定长度导入示例作业,所以熟悉该示例的读者会看到相似之处。如果您需要找到现有示例,只需访问 Spring Batch 主页下载版本(固定长度示例配置也可以在此处浏览)。
<batch>
<job id="fixedLengthImportJob" volatile="false">
<simple-step id="step1" chunk-size="50" save-restart-data="false"
allow-start-if-complete="true" reader-ref="fileInputTemplate">
<processor>
<beans:bean
class="org.springframework.batch.sample.item.processor.TradeProcessor">
<property name="writer" ref="tradeDao" />
</beans:bean>
</processor>
<simple-completion-policy skipLimit="5" />
</simple-step>
<simple-step id="step2" chunk-size="200">
<jdbc-cursor-reader data-source-ref="dataSource">
<query><![CDATA[SELECT ID FROM T_TRADE ORDER BY ID WHERE PROCESSED='N']]></query>
</jdbc-cursor-reader>
<processor>
<beans:bean
class="org.springframework.batch.sample.item.processor.TradeUpdater">
<property name="dao" ref="tradeDao" />
</beans:bean>
</processor>
</simple-step>
<tasklet-step id="step3" chunk-size="1">
<tasklet>
<beans:bean
class="org.springframework.batch.sample.sproc.TradeSummarizer"
p:dataSource-ref="dataSource" />
</tasklet>
</tasklet-step>
</job>
<!-- INFRASTRUCTURE SETUP -->
<flat-file-reader id="fileInputTemplate"
resource="data/fixedLengthImportJob/input/20070122.teststream.ImportTradeDataStep.txt"
field-set-mapper-ref="fieldSetMapper"
validator-ref="fixedValidator">
<fixed-length-tokenizer>
<columns>
ISIN=1-12 Quantity=13-15 Price=16-20 Customer=21-29
</columns>
</fixed-length-tokenizer>
</flat-file-reader>
<beans:bean id="fixedValidator"
class="org.springframework.batch.item.validator.SpringValidator">
<property name="validator">
<bean id="tradeValidator"
class="org.springmodules.validation.valang.ValangValidator">
<property name="valang">
<value>
<![CDATA[
{ isin : length(?) < 13 : 'ISIN too long' : 'isin_length' : 12}
]]>
</value>
</property>
</bean>
</property>
</beans:bean>
<beans:bean id="tradeDao"
class="org.springframework.batch.sample.dao.JdbcTradeWriter">
<property name="jdbcTemplate" ref="jdbcTemplate" />
<property name="incrementer">
<bean parent="incrementerParent">
<property name="incrementerName" value="TRADE_SEQ" />
</bean>
</property>
</beans:bean>
<beans:bean id="fieldSetMapper"
class="org.springframework.batch.sample.mapping.TradeFieldSetMapper" />
</batch>
请注意,Job和StepStep 实现细节是如何隐藏的 -<simple-step/>与<tasklet-step/>之间存在差异,但唯一可见的差异是用户需要了解的那些。用户无需知道该Step接口有不同的实现来支持此配置,但存在面向项目(item-oriented)和面向任务(task-oriented)的步骤方法的差异并未隐藏。这正是我们认为对用户重要的。当我们起草这些 XML 示例时,我们从现有的 Spring Batch 示例中选取了几个,并进行修改,直到包含相同的配置信息,但在大多数情况下,文件总大小下降了 50% 或更多。这一定意味着我们走在正确的轨道上。
这是一个快速但深入的 Spring Batch 及其最近一些变化的探讨。关于我们使用和实现该框架的经验,还有很多有趣的细节可以与您分享。我的JavaOne演讲已被接受,这意味着您可以期待在五月份在旧金山学习更多内容,并听到更多真实的批处理示例。此外,随着 2.5 发布列车启动其旅程(从用户的角度来看是这样!),请关注本博客的更多内容。
最后,我需要向 Lucas Ward 和 Ben Hale 致敬,他们在 Spring Batch 开发过程中发挥了重要作用。我还要欢迎 Robert Kasanicky 成为我们最新的提交者(committer)—— Robert 为 Spring Batch 贡献了一些高质量的代码,我相信在我们完成 1.0 版本并开始下一个主要版本的工作时,他会继续这样做。如果还有其他人有兴趣贡献,Robert 遵循了正常流程,在论坛和 JIRA 上活跃,贡献想法和(关键的)补丁。我提名了他,我们进行了投票,现在他正式成为团队的一员。
如果文章中有任何需要澄清的地方,请随时在此处评论。关于 Spring Batch 的一般讨论,请使用论坛。Spring Batch 的主页在此处,或者可以很容易地从Spring 主网站找到