spring batch动态示例及原理

文章目录

JobController

java 复制代码
@RestController
public class JobController {

    @Autowired(required = false)
    private JobLauncher msgJobLauncher4;

    @Autowired(required = false)
    private Job msgJob4;

    @RequestMapping("msgJob4")
    public String msgJob4() {
        try {
            JobExecution jobExecution = msgJobLauncher4.run(msgJob4, new JobParametersBuilder()
                    .addString("time", System.currentTimeMillis() + "")
                    .toJobParameters());
            return "ok";
        } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException |
                 JobParametersInvalidException e) {
            throw new RuntimeException(e);
        }
    }

    @Autowired(required = false)
    private JobLauncher msgJobLauncher5;

    @Autowired(required = false)
    private Job msgJob5;

    @RequestMapping("msgJob5")
    public String msgJob5(@RequestParam(name = "key", defaultValue = "dft") String key) {
        try {
            JobExecution jobExecution = msgJobLauncher5.run(msgJob5, new JobParametersBuilder()
                    .addString("time", System.currentTimeMillis() + "")
                    .addString("key", key)
                    .toJobParameters());
            return "ok";
        } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException |
                 JobParametersInvalidException e) {
            throw new RuntimeException(e);
        }
    }

}

WriteFlatFileMsgJobConfig4

先写个100条数据 ,待会去读

java 复制代码
@Slf4j
@Configuration
public class WriteFlatFileMsgJobConfig4 {

    @Autowired
    private JobRepository jobRepository;

    @Autowired
    private PlatformTransactionManager txm;

    @Autowired
    private MsgMapper msgMapper;

    @Bean
    public JobLauncher msgJobLauncher4() {
        TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher();
        jobLauncher.setJobRepository(jobRepository);
        return jobLauncher;
    }

    @Bean
    public Job msgJob4() {
        return new JobBuilder("msgJob4", jobRepository)
                .start(msgStep4())
                .build();
    }

    private Step msgStep4() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(1);
        executor.setMaxPoolSize(1);
        executor.afterPropertiesSet();

        return new StepBuilder("msgStep4", jobRepository)
                .<Person, Person>chunk(1, txm)
                .reader(msgReader4())
                .processor(msgProcessor4())
                .writer(msgWriter4())
                .taskExecutor(executor)
                .faultTolerant()
                .skip(Exception.class)
                .skipLimit(3)
                .build();
    }

    @Bean
    @StepScope
    public ItemReader<Person> msgReader4() {

        ItemReader<Person> itemReader = new ItemReader<>() {
            private int num = 1;
            private static final int DEFAULT_MAX_NUM = 100;

            @Override
            public Person read() throws Exception {
                synchronized (this) {
                    if (num <= DEFAULT_MAX_NUM) {
                        Person person = new Person();
                        person.setId(num);
                        person.setName("zzhua" + num);
                        person.setAge(new Random().nextInt(30));
                        System.out.println(person);
                        num++;
                        return person;
                    }
                    return null;
                }
            }
        };

        System.out.println("create msgReader4...: " + itemReader);

        return itemReader;
    }

    private ItemProcessor<Person, Person> msgProcessor4() {
        return new ItemProcessor<Person, Person>() {
            @Override
            public Person process(Person item) throws Exception {
                return item;
            }
        };
    }

    private ItemWriter<Person> msgWriter4() {
        return new FlatFileItemWriterBuilder<Person>()
                .name("msgWriter4")
                .delimited()
                .names("id", "name", "age")
                .resource(new FileSystemResource(new File(System.getProperty("user.dir") + "\\file\\person.txt")))
                .build();
    }

}

ReadFlatFileMsgJobConfig5

java 复制代码
@Configuration
public class ReadFlatFileMsgJobConfig5 {

    @Autowired
    private JobRepository jobRepository;

    @Autowired
    private PlatformTransactionManager txm;

    @Autowired
    private MsgMapper msgMapper;

    @Bean
    public JobLauncher msgJobLauncher5() {
        TaskExecutorJobLauncher jobLauncher = new TaskExecutorJobLauncher();
        jobLauncher.setJobRepository(jobRepository);
        return jobLauncher;
    }

    @Bean
    public Job msgJob5() {
        return new JobBuilder("msgJob5", jobRepository)
                .start(msgStep5())
                .build();
    }

    private Step msgStep5() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

		// 注意,可以使用多线程去读哦(支持reader使用@StepScope)
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(10);
        executor.afterPropertiesSet();

        return new StepBuilder("msgStep5", jobRepository)
                .<Person, Person>chunk(1, txm)
                .reader(msgReader5(null))
                .processor(msgProcessor5())
                .writer(msgWriter5())
                .taskExecutor(executor)
                .faultTolerant()
                .skip(Exception.class)
                .skipLimit(3)
                .build();
    }

    @Bean
    @StepScope // 必须声明为ItemStreamReader,否则会报错
    public ItemStreamReader<Person> msgReader5(
    	// 动态获取job的执行参数
    	@Value("#{jobParameters['key']}") String key
   	) {

        Properties props = new Properties();

        String readFileName = "person.txt";
        try {
        	// 动态读取文件中配置的属性名
            props.load(new FileReader(System.getProperty("user.dir") + "\\file\\file.properties"));
            readFileName = props.getProperty("readFileName");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        FlatFileItemReader<Person> itemReader = new FlatFileItemReaderBuilder<Person>()
            .name("msgReader5")
            .resource(new FileSystemResource(new File(System.getProperty("user.dir") + "\\file\\" + readFileName)))
            .delimited()
            .names("id", "name", "age")
            .targetType(Person.class)
            .build();

        System.out.println("create msgReader5..." + itemReader + "key: " + key);

        return itemReader;
    }

    private ItemProcessor<Person, Person> msgProcessor5() {
        return new ItemProcessor<Person, Person>() {
            @Override
            public Person process(Person item) throws Exception {
                System.out.println("processor->" + item);
                return item;
            }
        };
    }

    private ItemWriter<Person> msgWriter5() {
        return new ItemWriter<Person>() {
            @Override
            public void write(Chunk<? extends Person> chunk) throws Exception {
                System.out.println(chunk);
            }
        };
    }
    
}

file.properties

properties 复制代码
readFileName=person.txt

@StepScope的前因后果

1、执行step之前,维护着全局唯一的stepExecution
2、多线程任务通过TaskExecutorRepeatTemplate开启,每个线程执行自己的任务,执行任务之前,先将全局唯一的stepExecution注册进去

关键就在这里,只要stepExecution是唯一的,那么获取的stepContext就是同一个,那么如果一个step开了多线程去跑,那么肯定能保证stepExecution是同一个,那么stepContext就是所有线程所共享,那么执行step步骤的不同线程中获取的就是同一个stepContext。

3、再看StepScope获取bean的逻辑

再看获取stepContext的逻辑

如下继续调用

针对多个线程而言,每个线程在执行任务时,都是将全局唯一共享的stepExecution绑定到当前自己的线程,那么每个线程在此处肯定拿到的时同一个stepContext,于是每次代理从stepScope中获取的肯定是第一次创建的对象了

为什么要声明为ItemStreamReader

至于为什么要声明为ItemStream呢?因为@StepScope标记当前bean返回的是仅实现了ItemReader代理对象,判断时并不会认为它实现了ItemStream接口,因此默认就不会添加到streams中,所以必须显式声明为ItemStreamReader,如果需要动态写,同理可声明为IteamStreamWriter

1、添加的过程步骤

最终在构建step对象时,添加到了streams中

2、调用过程






相关推荐
云烟成雨TD2 天前
Spring AI Alibaba 1.x 系列【6】ReactAgent 同步执行 & 流式执行
java·人工智能·spring
Java成神之路-2 天前
SpringMVC 响应实战指南:页面、文本、JSON 返回全流程(Spring系列13)
java·spring·json
砍材农夫2 天前
spring-ai 第六模型介绍-聊天模型
java·人工智能·spring
云烟成雨TD2 天前
Spring AI Alibaba 1.x 系列【5】ReactAgent 构建器深度源码解析
java·人工智能·spring
Flittly2 天前
【SpringAIAlibaba新手村系列】(15)MCP Client 调用本地服务
java·笔记·spring·ai·springboot
Flittly2 天前
【SpringAIAlibaba新手村系列】(14)MCP 本地服务与工具集成
java·spring boot·笔记·spring·ai
mfxcyh2 天前
基于xml、注解、JavaConfig实现spring的ioc
xml·java·spring
Flittly2 天前
【SpringAIAlibaba新手村系列】(13)Tool Calling 函数工具调用技术
java·spring boot·spring·ai
xdscode2 天前
Spring 依赖注入方式全景解析
java·后端·spring