跳到主要内容

常见问题解答

QWen Plus 中英对照 Frequently Asked Questions

是否可以在多个线程或多进程中执行任务?

这里有三种方法可以解决这个问题——但我们建议在分析此类需求时保持谨慎(是否真的必要?)。

  • 为步骤添加一个 TaskExecutor。提供的用于配置步骤的 `StepBuilder` 有一个可以设置的 "taskExecutor" 属性。只要步骤本质上是可重启的(即幂等的),这种方式就可以正常工作。并行作业示例展示了它在实际中的应用方式——这使用了“处理指示器”模式,在业务事务中将输入记录标记为已完成。

  • 使用 PartitionStep 明确地将步骤执行分配到多个 Step 实例中。Spring Batch 提供了该主要策略的本地多线程实现(PartitionHandler),这使其成为 IO 密集型作业的绝佳选择。请记住,对于以这种方式执行的步骤中的有状态组件,要使用 scope="step",以便为每次步骤执行创建单独的实例,并避免线程之间的干扰。

  • 使用 spring-batch-integration 模块中实现的远程分块(Remote Chunking)方法。这需要一些持久化的中间件(例如 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 作为触发器,通过 Cron 表达式和 Spring Core 提供的 SchedulerFactoryBean 来启动一个 Spring Batch 作业。

如何使用 Spring Batch 安排作业?

使用调度工具。外面有很多这样的工具。例如:Quartz、Control-M、Autosys。Quartz 没有 Control-M 或 Autosys 那么多功能——它旨在轻量级。如果你想要更轻量级的解决方案,可以直接使用操作系统提供的功能(如 cronat 等)。

简单的顺序依赖关系可以使用 Spring Batch 的作业步骤模型和 Spring Batch 中的非顺序特性来实现。我们认为这是非常常见的。事实上,这也有助于纠正调度器的一个常见误用——配置了成百上千个作业,其中许多作业并非独立,而只是依赖于另一个作业。

Spring Batch如何允许项目优化性能和可扩展性(通过并行处理或其他方式)?

我们将其视为 JobStep 的其中一个角色。特定的 Step 实现关注的是如何将业务逻辑拆分,并在并行进程中或处理器之间高效共享(参见 PartitionStep)。这里可以使用多种技术来实现这一目标。其核心是一组并发的远程调用,用于调用分布式代理以处理某些业务逻辑。由于业务处理通常已经是模块化的——例如,输入一个项目并对其进行处理——Spring Batch 可以通过多种方式对分布策略进行优化。我们有经验的一种实现方式是使用一组远程 Web 服务来处理业务逻辑。我们将输入数据的一组特定主键范围发送到多个远程调用中。同样的基本策略也可以应用于任何 Spring Remoting 协议(如普通 RMI、HttpInvoker、JMS、Hessian 等),只需在执行层配置中更改几行代码即可。

如何使用消息传递来扩展批处理架构?

从现有的项目中,有大量的实际证据表明,管道方法对批处理非常有益,可以提高系统的弹性和吞吐量。我们经常面临关键任务型应用,其中审计跟踪是必不可少的,且需要保证处理的可靠性,但同时在高负载下对性能有极其严格的限制,或者高吞吐量能带来竞争优势。

Matt Welsh 的工作表明,分阶段事件驱动架构(SEDA)相比更 rigid 的处理架构具有巨大的优势,而面向消息的中间件(JMS、AQ、MQ、Tibco 等)为我们提供了许多开箱即用的弹性能力。在下游和上游阶段之间存在反馈的系统中,这种架构特别有益,因为可以根据需求量调整消费者的数量。那么,这与 Spring Batch 有何关系呢?spring-batch-integration 项目已经在 Spring Integration 中实现了这一模式,并可以用于扩展任何需要处理大量项目的步骤的远程处理。特别是,请参阅 "chunk" 包,以及其中的 ItemWriterChunkHandler 实现。