开启自动运行
配置文件
spring:
batch:
job:
names: simpleJob #自动执行的Job的名字
enabled: true #启用
initialize-schema: ALWAYS #是否初始化数据库
table-prefix: # 生成的表格前缀
schema: #生成表格的脚本
添加注解
如果需要自动运行job除了配置外需要引入
@EnableBatchProcessing
自动运行注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(BatchConfigurationSelector.class)
public @interface EnableBatchProcessing {
/**
* Indicate whether the configuration is going to be modularized into multiple application contexts. If true then
* you should not create any @Bean Job definitions in this context, but rather supply them in separate (child)
* contexts through an {@link ApplicationContextFactory}.
*
* @return boolean indicating whether the configuration is going to be
* modularized into multiple application contexts. Defaults to false.
*/
boolean modular() default false;
}
自动配置原理
注解调用配置
引入 @EnableBatchProcessing
注解后会调用 @Import(BatchConfigurationSelector.class)
BatchConfigurationSelector
BatchConfigurationSelector
会调用其 selectImports()
方法
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
Class<?> annotationType = EnableBatchProcessing.class;
AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(annotationType.getName(), false));
Assert.notNull(attributes, String.format("@%s is not present on importing class '%s' as expected",annotationType.getSimpleName(), importingClassMetadata.getClassName()));
String[] imports;
if (attributes.containsKey("modular") && attributes.getBoolean("modular")) {
imports = new String[] { ModularBatchConfiguration.class.getName() };
}
else {
imports = new String[] { SimpleBatchConfiguration.class.getName() };
}
return imports;
}
根据 @EnableBatchProcessing
modular属性的配置
- true ModularBatchConfiguration
- 其他 SimpleBatchConfiguration
SimpleBatchConfiguration
- 该配置最大的问题在于懒加载最后初始化的Batch组件均为代理对象
@Override
@Bean
public JobRepository jobRepository() throws Exception {
return createLazyProxy(jobRepository, JobRepository.class);
}
- 当需要的时候会调用SimpleBatchConfiguration.ReferenceTargetSource.createObject()
@Override
protected Object createObject() throws Exception {
initialize();
return reference.get();
}
- 里面会调用SimpleBatchConfiguration.initialize()
他会将通过getConfigurer()
取到的BatchConfigurer
配置生成的bean取出来去使用
protected void initialize() throws Exception {
if (initialized) {
return;
}
BatchConfigurer configurer = getConfigurer(context.getBeansOfType(BatchConfigurer.class).values());
jobRepository.set(configurer.getJobRepository());
jobLauncher.set(configurer.getJobLauncher());
transactionManager.set(configurer.getTransactionManager());
jobRegistry.set(new MapJobRegistry());
jobExplorer.set(configurer.getJobExplorer());
initialized = true;
}
- 调用AbstractBatchConfiguration.getConfigurer()获取配置类
private BatchConfigurer configurer;
·
·
·
protected BatchConfigurer getConfigurer(Collection<BatchConfigurer> configurers) throws Exception {
if (this.configurer != null) {//如果configurer不为空 返回
return this.configurer;
}
if (configurers == null || configurers.isEmpty()) {
if (dataSource == null) {
DefaultBatchConfigurer configurer = new DefaultBatchConfigurer();
configurer.initialize();
this.configurer = configurer;
return configurer;
} else {
DefaultBatchConfigurer configurer = new DefaultBatchConfigurer(dataSource);
configurer.initialize();
this.configurer = configurer;
return configurer;
}
}
if (configurers.size() > 1) {
throw new IllegalStateException(
"To use a custom BatchConfigurer the context must contain precisely one, found "
+ configurers.size());
}
this.configurer = configurers.iterator().next();
return this.configurer;
}
5.BatchConfigurerConfiguration初始化BatchConfigurer
@ConditionalOnClass({PlatformTransactionManager.class})
@ConditionalOnMissingBean({BatchConfigurer.class})
@Configuration
class BatchConfigurerConfiguration {
BatchConfigurerConfiguration() {}
@Configuration
@ConditionalOnClass(name = {"javax.persistence.EntityManagerFactory"})
@ConditionalOnBean(name = {"entityManagerFactory"})
static class JpaBatchConfiguration {
JpaBatchConfiguration() {
}
@Bean
public JpaBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers, EntityManagerFactory entityManagerFactory) {
return new JpaBatchConfigurer(properties, dataSource, (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable(), entityManagerFactory);
}
}
@Configuration
@ConditionalOnMissingBean(name = {"entityManagerFactory"})
static class JdbcBatchConfiguration {
JdbcBatchConfiguration() {
}
@Bean
public BasicBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
return new BasicBatchConfigurer(properties, dataSource, (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable());
}
}
}
@Configuration
@ConditionalOnClass({JobLauncher.class, DataSource.class, JdbcOperations.class})
@AutoConfigureAfter({HibernateJpaAutoConfiguration.class})
@ConditionalOnBean({JobLauncher.class})
@EnableConfigurationProperties({BatchProperties.class})
@Import({BatchConfigurerConfiguration.class})
public class BatchAutoConfiguration {
private final BatchProperties properties;
private final JobParametersConverter jobParametersConverter;
public BatchAutoConfiguration(BatchProperties properties, ObjectProvider<JobParametersConverter> jobParametersConverter) {
this.properties = properties;
this.jobParametersConverter = (JobParametersConverter)jobParametersConverter.getIfAvailable();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean({DataSource.class})
public BatchDataSourceInitializer batchDataSourceInitializer(DataSource dataSource, ResourceLoader resourceLoader) {
return new BatchDataSourceInitializer(dataSource, resourceLoader, this.properties);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(
prefix = "spring.batch.job",
name = {"enabled"},
havingValue = "true",
matchIfMissing = true
)
public JobLauncherCommandLineRunner jobLauncherCommandLineRunner(JobLauncher jobLauncher, JobExplorer jobExplorer) {
JobLauncherCommandLineRunner runner = new JobLauncherCommandLineRunner(jobLauncher, jobExplorer);
String jobNames = this.properties.getJob().getNames();
if(StringUtils.hasText(jobNames)) {
runner.setJobNames(jobNames);
}
return runner;
}
@Bean
@ConditionalOnMissingBean({ExitCodeGenerator.class})
public JobExecutionExitCodeGenerator jobExecutionExitCodeGenerator() {
return new JobExecutionExitCodeGenerator();
}
@Bean
@ConditionalOnMissingBean({JobOperator.class})
public SimpleJobOperator jobOperator(JobExplorer jobExplorer, JobLauncher jobLauncher, ListableJobLocator jobRegistry, JobRepository jobRepository) throws Exception {
SimpleJobOperator factory = new SimpleJobOperator();
factory.setJobExplorer(jobExplorer);
factory.setJobLauncher(jobLauncher);
factory.setJobRegistry(jobRegistry);
factory.setJobRepository(jobRepository);
if(this.jobParametersConverter != null) {
factory.setJobParametersConverter(this.jobParametersConverter);
}
return factory;
}
}