我们如何在 Spring 批处理步骤中将 `MethodInvokingTaskletAdapter` 的结果作为 reader?

How can we take the result of `MethodInvokingTaskletAdapter` as a reader in the Spring Batch Step?

我们如何在 Spring 批处理步骤中将 MethodInvokingTaskletAdapter 的结果作为 reader?参考 - https://docs.spring.io/spring-batch/docs/current/reference/html/index-single.html#taskletStep and https://github.com/spring-projects/spring-batch/pull/567

这是我开发的代码

JobConfiguration.java

@Configuration
public class JobConfiguration {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    
    @Bean
    public CustomService service() {
        return new CustomService();
    }
    
    @StepScope
    @Bean
    public MethodInvokingTaskletAdapter methodInvokingTasklet() {
        MethodInvokingTaskletAdapter methodInvokingTaskletAdapter = new MethodInvokingTaskletAdapter();
        methodInvokingTaskletAdapter.setTargetObject(service());
        methodInvokingTaskletAdapter.setTargetMethod("getEmployees");
        return methodInvokingTaskletAdapter;
    }
    
    @Bean
    public Job methodInvokingJob() {
        return this.jobBuilderFactory.get("methodInvokingJob")
                .start(methodInvokingStep())
                .build();
    }

    @Bean
    public Step methodInvokingStep() {
        // Looking to configure the Chunk based Step here, dont know how to do using MethodInvokingTaskletAdapter
        return this.stepBuilderFactory.get("methodInvokingStep")
                .tasklet(methodInvokingTasklet())
                .build();
    }
}

CustomService.java

public class CustomService {
    public void serviceMethod(String message) {
        System.out.println(message);
    }
    
    public void invokeMethod() {
        System.out.println("=============== Your method has executed !");
    }
    
    public List<Employee> getEmployees(){
        // In real world, it will be an GET API call to XYZ system
        List<Employee> employees = new ArrayList<>();
        employees.add(Employee.builder().firstName("Ravi").lastName("Shankar").email("ravi.shankar@gmail.com").age(30).build());
        employees.add(Employee.builder().firstName("Parag").lastName("Rane").email("parag.rane@gmail.com").age(11).build());
        employees.add(Employee.builder().firstName("Priya").lastName("Pande").email("priya.pande@gmail.com").age(40).build());
        employees.add(Employee.builder().firstName("Kiran").lastName("khot").email("kiran.khot@gmail.com").age(50).build());
        return employees;
    }
}

Employee.java

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Employee {
    private String firstName;
    private String lastName;
    private String email;
    private int age;
}

MethodInvokingTaskletApplication.java

@EnableBatchProcessing
@SpringBootApplication
public class MethodInvokingTaskletApplication {

    public static void main(String[] args) {
        SpringApplication.run(MethodInvokingTaskletApplication.class, args);
    }
}

要回答你的问题,你不能。 MethodInvokingTaskletAdapter 旨在使 POJO 适应 Tasklet。我们有一个 ItemReaderAdapter,您可以使用它来使 POJO 适应 ItemReader。您可以在此处的文档中阅读相关信息:https://docs.spring.io/spring-batch/docs/current/api/org/springframework/batch/item/adapter/ItemReaderAdapter.html

现在您的服务将遇到配置问题,因为对委托 POJO 的每次调用都被视为一个项目。这意味着您配置的项目将是 List<Employee> 而不仅仅是 Employee。鉴于您的配置声明它不是真正的服务,我假设您的真正服务应该 return 每次调用 Employee 并且一旦结果耗尽 null

要更新示例中的配置(使用问题中配置的服务):

...
    @StepScope
    @Bean
    public ItemReaderAdapter itemReader() {
        ItemReaderAdapter reader = new ItemReaderAdapter();
        reader.setTargetObject(service());
        reader.setTargetMethod("getEmployees");
        return reader;
    }
    
    @Bean
    public Job methodInvokingJob() {
        return this.jobBuilderFactory.get("methodInvokingJob")
                .start(methodInvokingStep())
                .build();
    }

    @Bean
    public Step methodInvokingStep() {
        return this.stepBuilderFactory.get("methodInvokingStep")
                .<List<Employee>, List<Employee>>chunk(methodInvokingTasklet())
                .reader(itemReader())
                // You'll need to define a writer...
                .writer(itemWriter())
                .build();
    }
    ...