常见问题
是否可以在多线程或多进程中执行作业?
处理这个问题有三种方法——但我们建议在分析此类需求时保持谨慎(这真的有必要吗?)。
-
为步骤添加
TaskExecutor。用于配置步骤的StepBuilder提供了一个 "taskExecutor" 属性可供设置。只要步骤本身是可重启的(实际上是幂等的),此方法即可生效。并行作业示例展示了它在实践中如何工作——该示例使用 "process indicator" 模式在业务事务内部将输入记录标记为已完成。 -
使用
PartitionStep将步骤执行显式地拆分到多个 Step 实例中。Spring Batch 为此主要策略提供了一个本地多线程实现(PartitionHandler),这使其成为 IO 密集型作业的绝佳选择。请记住,对于以这种方式执行的步骤中的有状态组件,要使用scope="step",以便为每次步骤执行创建独立的实例,并且线程之间不会产生串扰。 -
使用
spring-batch-integration模块中实现的远程分块方法。这需要一些持久化的中间件(例如 JMS)来确保驱动步骤与远程工作节点之间的可靠通信。其基本思想是在驱动进程上使用一个特殊的ItemWriter,并在工作进程上使用监听器模式(通过ChunkProcessor)。
如何使项目读取器线程安全?
你可以同步 read() 方法(例如,通过将其包装在一个执行同步操作的委托器中)。请注意,这样做会失去可重启性,因此最佳实践是将该步骤标记为不可重启。为了确保安全(并提高效率),你还可以在读取器上设置 saveState=false。
Spring Batch 在灵活策略与默认实现使用上的理念是什么?能否为某个属性添加公共 getter 方法?
Spring Batch 为框架开发者(而非业务逻辑实现者)提供了众多扩展点。我们期望用户能够创建更具体的自定义策略,并将其集成到框架中,以控制诸如提交间隔(CompletionPolicy)、异常处理规则(ExceptionHandler)等众多行为。
通常我们不建议用户扩展框架类。Java语言在将类和接口标记为内部实现方面提供的灵活性有限。一般来说,你可以预期org.springframework.batch.*包中源码树顶层的所有内容都是公开的,但不一定适合子类化。我们不鼓励扩展大多数策略的具体实现,而是推荐采用组合或分支的方式。如果你的代码仅使用Spring Batch的接口,这将为你提供最大的可移植性。
Spring Batch 与 Quartz 有何不同?它们是否可以在一个解决方案中共存?
Spring Batch 与 Quartz 的目标不同。Spring Batch 提供处理大量数据的功能,而 Quartz 提供调度任务的功能。因此,Quartz 可以补充 Spring Batch,但并非互斥的技术。一种常见的组合是使用 Quartz 作为 Spring Batch 作业的触发器,通过 Cron 表达式和 Spring Core 便捷的 SchedulerFactoryBean 来实现。
如何用 Spring Batch 调度作业?
使用调度工具。市面上有很多这类工具,例如:Quartz、Control-M、Autosys。Quartz 不具备 Control-M 或 Autosys 的所有功能——它被设计为轻量级工具。如果你需要更轻量级的方案,可以直接使用操作系统自带的工具(如 cron、at 等)。
简单的顺序依赖可以通过Spring Batch的作业步骤模型以及其非顺序特性来实现。我们认为这是相当常见的做法。实际上,这使得纠正调度器的一个常见误用变得更容易——配置了数百个作业,其中许多并非独立,而仅依赖于另一个作业。
Spring Batch 如何允许项目优化性能和可扩展性(通过并行处理或其他方式)?
我们认为这是Job或Step的职责之一。Step的具体实现负责处理将业务逻辑拆分并在并行进程或处理器之间高效共享的问题(参见PartitionStep)。有多种技术可以在此发挥作用。其核心是一组对分布式代理的并发远程调用,这些代理能够处理某些业务处理。由于业务处理通常已经模块化——例如输入一个项目并处理它——Spring Batch可以通过多种方式制定分发策略。我们已有一些经验的一种实现是使用一组远程Web服务来处理业务处理。我们将输入的主键特定范围发送给每个远程调用。相同的基本策略适用于任何Spring远程协议(普通RMI、HttpInvoker、JMS、Hessian等),只需在执行层配置中更改几行代码即可。
如何利用消息传递来扩展批处理架构?
现有项目的诸多实践证据表明,采用流水线方法进行批处理具有显著优势,能够提升系统韧性与吞吐量。我们经常面临关键业务应用场景,这些场景既需要完整的审计追踪和可靠的处理保障,又对负载下的性能有着极为严苛的要求,或需要通过高吞吐量获取竞争优势。
Matt Welsh的研究表明,分阶段事件驱动架构(SEDA)相较于更僵化的处理架构具有巨大优势,而面向消息的中间件(JMS、AQ、MQ、Tibco等)则为我们提供了开箱即用的强大弹性。在下游与上游阶段存在反馈的系统中,这种架构尤其有益,因为可以根据需求动态调整消费者数量。那么这与 Spring Batch 如何结合呢?spring-batch-integration 项目已在 Spring Integration 中实现了这种模式,可用于扩展任何包含大量待处理条目的步骤的远程处理能力。请特别关注其中的 "chunk" 包,以及其中的 ItemWriter 和 ChunkRequestHandler 实现。