아래는 SpringBoot 에서 명령행(Command line)으로 Spring Batch Job을 실행하는 방법이다.
compile('org.springframework.boot:spring-boot-starter-batch') // 2.x bootJar { mainClassName = "my.boot.batch.BatchApplication" } // 1.x - 지정하지 않으면 자동으로 @SpringBootApplication 애노테이션이 붙은 클래스로 자동 지정됨. bootRepackage { mainClass = "my.boot.batch.BatchApplication" }
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration
와 org.springframework.boot.autoconfigure.batch.BasicBatchConfigurer
를 분석해보면 작동 원리를 알 수 있다.JobLauncherCommandLineRunner
는 spring.batch.job.enabled=true
일 때 자동 생성되며, spring.batch.job.names
에 쉼표로 구분되어 지정된 Job들을 실행한다. 단, spring.batch.job.names
가 존재하지 않으면 모든 Job을 실행해버린다!@EnableBatchProcessing
에 의해 생성된 JobLauncher
, JobExplorer
를 주입받고, param1=value1 param2=value2
로 준 값이 자동으로 Job Parameter key/value로 들어가게 된다.@Primary
DataSource
를 자동으로 사용한다. 보통 이 경우 문제가 된다. 별도 DB를 따로 사용하게 설정하려면 Spring Framework Batch 에서 설정 Override 참조.@Slf4j @EnableBatchProcessing @SpringBootApplication @Import(각종기타 설정 import) public class BatchApplication extends DefaultBatchConfigurer { public static void main(String[] args) { int exitCode = SpringApplication.exit(SpringApplication.run(BatchApplication.class, args)); System.exit(exitCode); } @Value("${spring.batch.job.names:NONE}") private String jobNames; // 어디선가 미리 생성해둔 spring batch 용 database @Autowired @Override public void setDataSource(@Qualifier("batchDataSource") DataSource batchDataSource) { super.setDataSource(batchDataSource); } // spring.batch.job.names 를 지정하지 않으면 모든 Job이 실행돼 버리기 때문에 // 방어차원에서 넣은 job.names validation 처리 @PostConstruct public void validateJobNames() { log.info("jobNames : {}", jobNames); if (jobNames.isEmpty() || jobNames.equals("NONE")) { throw new IllegalStateException("spring.batch.job.names=job1,job2 형태로 실행을 원하는 Job을 명시해야만 합니다!"); } } }
DefaultBatchConfigurer
사용시에 이 클래스내에서transactionManager
를 batchDataSource 용으로 생성해버려서 원래 애플리케> 이션의
DataSourceTransactionManagerAutoConfiguration.DataSourceTransactionManagerConfiguration 가 작동하지 않게 된다.
따라서 항상 애플리케이션용 DataSource에 대한 transactionManager를 항상 명시적으로 만들어주고 @Primary 설정을 해줘야 한다.
@Slf4j @Configuration // 아래를 통해 실행 대상 job으로 들어갔을 때만 해당 Job 설정이 수행되게 하면 불필요한 설정 부담을 줄일 수 있고 // 실수로 job이 실행되는 것을 막을 수 있다. @ConditionalOnProperty(name = "spring.batch.job.names", havingValue = "helloJob") public class HelloBatchConfiguration { @Autowired private JobBuilderFactory jobBuilderFactory; @Autowired private StepBuilderFactory stepBuilderFactory; public HelloBatchConfiguration() { // job.names가 helloJob 일 때만 생성자의 아래 로그가 출력됨. log.info("======== Hello Job configured!! =========="); } @Bean(name = "helloJob") public Job helloJob() { return jobBuilderFactory.get("helloJob") .start(step()) .build(); } @Bean public Step step() { return stepBuilderFactory.get("taskletStep").tasklet(new Tasklet() { @Override public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception { log.info("==== Tasklet called...."); Map<String, Object> jobParameters = chunkContext.getStepContext().getJobParameters(); // 모든 Job Parameter 출력 jobParameters.forEach((key, value) -> { log.info("key : {}, value : {}", key, value); }); return RepeatStatus.FINISHED; } }).build(); } }
spring.batch.job.enabled=true
여야 JobLauncherCommandLineRunner
가 활성화 된다.spring: batch: job: enabled: true initialize-schema: embedded main: web-application-type: NONE
spring.batch.initialize-schema
는 거의 항상 embdded
로 지정하며, 별도 DB 사용시에는 never
로 지정한다. always
인 경우는 거의 없다고 봄.spring-boot-starter-web
, spring-boot-starter-webflux
가 의존성에 없어야 하며, 만약 있다면 spring.main.web-application-type=NONE
으로 설정할 것.spring.batch.job.enabled=false
로 두고 JobLauncherTestUtils
로 런칭하게 하지 않으면 배치 Job이 두 번 실행된다. 첫번째 실행시 파라미터가 잘못 주입된다.
bootJar
로 jar를 생성하고
gradle bootJar
java -jar your-boot.jar --spring.batch.job.names=${JOB이름} \ JobParam1=ParamValue1 JobParam2=ParamValue2
spring.batch.job.names
는 쉼표로 구분하여 여러개도 지정 가능하다.spring.batch.job.names
를 명시하지 않으면 모든 job 이 다 실행된다.@org.springframework.boot.autoconfigure.batch.BatchDataSource
를 사용하여 batch 용 dataSource 지정이 가능하다.