1. Spring Batch 4.1 的新增功能

Spring Batch 4.1 版本增加了以下功能:

  • 新的@SpringBatchTestComments 可简化批处理组件的测试

  • 新的@EnableBatchIntegrationComments 可简化远程组块和分区配置

  • 新的JsonItemReaderJsonFileItemWriter支持 JSON 格式

  • 添加对使用 Bean 验证 API 验证 Item 的支持

  • 添加对 JSR-305Comments 的支持

  • FlatFileItemWriterBuilder API 的增强功能

1.1. @SpringBatchTest 注解

Spring Batch 提供了一些不错的 Util 类(例如JobLauncherTestUtilsJobRepositoryTestUtils)和测试执行监听器(StepScopeTestExecutionListenerJobScopeTestExecutionListener)来测试批处理组件。但是,为了使用这些 Util,必须显式配置它们。此版本引入了一个名为@SpringBatchTest的新 Comments,该 Comments 会自动将 Utilbean 和侦听器添加到测试上下文中,并使它们可用于自动装配,如以下示例所示:

@RunWith(SpringRunner.class)
@SpringBatchTest
@ContextConfiguration(classes = {JobConfiguration.class})
public class JobTest {

   @Autowired
   private JobLauncherTestUtils jobLauncherTestUtils;

   @Autowired
   private JobRepositoryTestUtils jobRepositoryTestUtils;

   @Before
   public void clearMetadata() {
      jobRepositoryTestUtils.removeJobExecutions();
   }

   @Test
   public void testJob() throws Exception {
      // given
      JobParameters jobParameters =
            jobLauncherTestUtils.getUniqueJobParameters();

      // when
      JobExecution jobExecution =
            jobLauncherTestUtils.launchJob(jobParameters);

      // then
      Assert.assertEquals(ExitStatus.COMPLETED,
                          jobExecution.getExitStatus());
   }

}

有关此新 Comments 的更多详细信息,请参见Unit Testing章。

1.2. @EnableBatchIntegration 注解

设置远程分块作业需要定义许多 bean:

  • 连接工厂,用于从消息传递中间件(JMS,AMQP 等)获取连接

  • MessagingTemplate,以将请求从主服务器发送到 Worker,然后再次返回

  • Spring Integration 从消息传递中间件获取消息的 Importing 通道和输出通道

  • 主端的特殊 Item 编写器(ChunkMessageChannelItemWriter)知道如何将数据块发送给工作人员进行处理和写入

  • 工 Writer 方的消息侦听器(ChunkProcessorChunkHandler)从主服务器接收数据

乍一 Watch 这可能有些令人生畏。此版本引入了名为@EnableBatchIntegration的新 Comments 以及新的 API(RemoteChunkingMasterStepBuilderRemoteChunkingWorkerBuilder)以简化配置。以下示例显示了如何使用新的 Comments 和 API:

@Configuration
@EnableBatchProcessing
@EnableBatchIntegration
public class RemoteChunkingAppConfig {

   @Autowired
   private RemoteChunkingMasterStepBuilderFactory masterStepBuilderFactory;

   @Autowired
   private RemoteChunkingWorkerBuilder workerBuilder;

   @Bean
   public TaskletStep masterStep() {
         return this.masterStepBuilderFactory
                         .get("masterStep")
                         .chunk(100)
                         .reader(itemReader())
                         .outputChannel(outgoingRequestsToWorkers())
                         .inputChannel(incomingRepliesFromWorkers())
                         .build();
   }

   @Bean
   public IntegrationFlow worker() {
         return this.workerBuilder
                         .itemProcessor(itemProcessor())
                         .itemWriter(itemWriter())
                         .inputChannel(incomingRequestsFromMaster())
                         .outputChannel(outgoingRepliesToMaster())
                         .build();
   }

   // Middleware beans setup omitted
}

这个新的 Comments 和构建器负责配置基础结构 Bean 的繁重工作。现在,您可以在工作端轻松配置一个主步骤以及一个 Spring Integration 流程。您可以在samples module中找到使用这些新 API 的远程分块示例,并在Spring 批处理集成一章中找到更多详细信息。

就像简化了远程组块配置一样,此版本还引入了新的 API 来简化远程分区设置:RemotePartitioningMasterStepBuilderRemotePartitioningWorkerStepBuilder。如果存在@EnableBatchIntegration,则可以在配置类中自动连接它们,如以下示例所示:

@Configuration
@EnableBatchProcessing
@EnableBatchIntegration
public class RemotePartitioningAppConfig {

   @Autowired
   private RemotePartitioningMasterStepBuilderFactory masterStepBuilderFactory;

   @Autowired
   private RemotePartitioningWorkerStepBuilderFactory workerStepBuilderFactory;

   @Bean
   public Step masterStep() {
            return this.masterStepBuilderFactory
               .get("masterStep")
               .partitioner("workerStep", partitioner())
               .gridSize(10)
               .outputChannel(outgoingRequestsToWorkers())
               .inputChannel(incomingRepliesFromWorkers())
               .build();
   }

   @Bean
   public Step workerStep() {
            return this.workerStepBuilderFactory
               .get("workerStep")
               .inputChannel(incomingRequestsFromMaster())
               .outputChannel(outgoingRepliesToMaster())
               .chunk(100)
               .reader(itemReader())
               .processor(itemProcessor())
               .writer(itemWriter())
               .build();
   }

   // Middleware beans setup omitted
}

您可以在Spring 批处理集成章中找到有关这些新 API 的更多详细信息。

1.3. JSON 支持

Spring Batch 4.1 添加了对 JSON 格式的支持。此版本引入了一个新的 Item 读取器,它可以读取以下格式的 JSON 资源:

[
  {
    "isin": "123",
    "quantity": 1,
    "price": 1.2,
    "customer": "foo"
  },
  {
    "isin": "456",
    "quantity": 2,
    "price": 1.4,
    "customer": "bar"
  }
]

与 XML 的StaxEventItemReader相似,新的JsonItemReader使用流 API 读取大块的 JSON 对象。 Spring Batch 支持两个库:

要添加其他库,您可以实现JsonObjectReader接口。

JsonFileItemWriter还支持写入 JSON 数据。有关 JSON 支持的更多详细信息,请参见ItemReaders 和 ItemWriters章。

1.4. Bean 验证 API 支持

此版本带来了一个名为BeanValidatingItemProcessor的新ValidatingItemProcessor实现,它使您可以验证使用 Bean Validation API(JSR-303)注解进行注解的 Item。例如,给定以下类型Person

class Person {

    @NotEmpty
    private String name;

    public Person(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

您可以通过在应用程序上下文中声明BeanValidatingItemProcessor bean 来验证 Item,并在面向块的步骤中将其注册为处理器:

@Bean
public BeanValidatingItemProcessor<Person> beanValidatingItemProcessor() throws Exception {
        BeanValidatingItemProcessor<Person> beanValidatingItemProcessor = new BeanValidatingItemProcessor<>();
        beanValidatingItemProcessor.setFilter(true);

        return beanValidatingItemProcessor;
}

1.5. JSR-305 支持

此版本增加了对 JSR-305 注解的支持。它利用 Spring Framework 的Null-safetyComments,并将它们添加到 Spring Batch 的所有公共 API 上。

这些注解不仅将在使用 Spring Batch API 时强制执行空安全性,而且还可以被 IDE 用于提供与空性有关的有用信息。例如,如果用户要实现ItemReader接口,则任何支持 JSR-305 注解的 IDE 都会生成以下内容:

public class MyItemReader implements ItemReader<String> {

        @Nullable
        public String read() throws Exception {
                return null;
        }

}

read方法中出现的@NullableComments 清楚表明此方法的约定表明它可能返回null。这将强制执行其 Javadoc 中所说的read方法在数据源耗尽时应返回null

1.6. FlatFileItemWriterBuilder 增强功能

此版本中添加的另一个小功能是简化了写入平面文件的配置。特别是,这些更新简化了定界文件和定宽文件的配置。以下是更改前后的示例。

// Before
@Bean
public FlatFileItemWriter<Item> itemWriter(Resource resource) {
        BeanWrapperFieldExtractor<Item> fieldExtractor =
            new BeanWrapperFieldExtractor<Item>();
        fieldExtractor.setNames(new String[] {"field1", "field2", "field3"});
        fieldExtractor.afterPropertiesSet();

        DelimitedLineAggregator aggregator = new DelimitedLineAggregator();
        aggregator.setFieldExtractor(fieldExtractor);
        aggregator.setDelimiter(";");

        return new FlatFileItemWriterBuilder<Item>()
                        .name("itemWriter")
                        .resource(resource)
                        .lineAggregator(aggregator)
                        .build();
}

// After
@Bean
public FlatFileItemWriter<Item> itemWriter(Resource resource) {
        return new FlatFileItemWriterBuilder<Item>()
                        .name("itemWriter")
                        .resource(resource)
                        .delimited()
                        .delimiter(";")
                        .names(new String[] {"field1", "field2", "field3"})
                        .build();
}