• Spring Batch源码阅读-初始化(三)


    例子

    @SpringBootApplication
    //可选参数预先初始化还是延迟初始化
    @EnableBatchProcessing(modular = true)
    public class SpringBatchDemoApplication {
        public static void main(String[] args) {
            SpringApplication.run(SpringBatchDemoApplication.class, args);
        }
    }

    我们使用spring batch 使用了 @EnableBatchProcessing 此注解

    @EnableBatchProcessing作用

    我们打开源码可以发现使用Import注解  import注解使用可以查看 https://www.cnblogs.com/LQBlog/p/15410425.html

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(BatchConfigurationSelector.class)//<1>
    public @interface EnableBatchProcessing {
    
        /**
         * Indicate whether the configuration is going to be modularized into multiple application contexts. If true then
         * you should not create any &#64;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;
    
    }

    <1>

     public class BatchConfigurationSelector implements ImportSelector {
                @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")) {
                        //<2> 导入ModularBatchConfiguration类
                        imports = new String[] { ModularBatchConfiguration.class.getName() };
                    }
                    else {
                        //是延迟初始化 点进去看代码可以看到get相关对象都是创建代理
                        imports = new String[] { SimpleBatchConfiguration.class.getName() };
                    }
    
                    return imports;
                }

    <2>

    /**
     * @Project spring-batch-test-demo
     * @PackageName springbatchsimpledemo.demo.batch.job.order
     * @ClassName Test
     * @Author qiang.li
     * @Date 2021/10/21 5:51 下午
     * @Description TODO
     */
    //proxyBeanMethods = false @Bean创建的对象将不使用代理
    @Configuration(proxyBeanMethods = false)
    public class ModularBatchConfiguration extends AbstractBatchConfiguration {
    
        @Autowired
        private ApplicationContext context;
         //初始化参考<>
        @Autowired(required = false)
        private Collection<BatchConfigurer> configurers;
    
        private AutomaticJobRegistrar registrar = new AutomaticJobRegistrar();
    
        /**
         * 获得jobRepository  主要是用来管理 job执行期间相关元数据的
         * 比如redis,文件,h2库 默认我们都是用的mysql
         * 可参考:org.springframework.batch.core.repository.support.SimpleJobRepository
         * @return
         * @throws Exception
         */
        @Override
        @Bean
        public JobRepository jobRepository() throws Exception {
            return getConfigurer(configurers).getJobRepository();
        }
    
        /**
         * 获得JobLauncher
         * JobLauncher主要job的容器 主要是管理job的启动
         * @return
         * @throws Exception
         */
        @Override
        @Bean
        public JobLauncher jobLauncher() throws Exception {
            //<3>可以看到获取是根据configures 是通过容器注入的
            return getConfigurer(configurers).getJobLauncher();
        }
    
        /**
         * job 执行期间的提交和关闭事物使用的事物管理器
         * @return
         * @throws Exception
         */
        @Override
        @Bean
        public PlatformTransactionManager transactionManager() throws Exception {
            // //<3>可以看到获取是根据configures 是通过容器注入的
            return getConfigurer(configurers).getTransactionManager();
        }
    
        /**
         * 与JobRepository 后续看源码再看具体用来做啥
         * @return
         * @throws Exception
         */
        @Override
        @Bean
        public JobExplorer jobExplorer() throws Exception {
            // //<3>可以看到获取是根据configures 是通过容器注入的
            return getConfigurer(configurers).getJobExplorer();
        }
    
        /**
         * J内部通过实现 LifecycleProcessor 当spring 容器启动成功时候自动实现将容器中job 注册到jobRegistry
    * *
    @return * @throws Exception */ @Bean public AutomaticJobRegistrar jobRegistrar() throws Exception { for (ApplicationContextFactory factory : context.getBeansOfType(ApplicationContextFactory.class).values()) { registrar.addApplicationContextFactory(factory); } return registrar; } }

    <3>

    org.springframework.batch.core.configuration.annotation.AbstractBatchConfiguration#getConfigurer

     protected BatchConfigurer getConfigurer(Collection<BatchConfigurer> configurers) throws Exception {
            //如果不为空就使用configurer
            if (this.configurer != null) {
                return this.configurer;
            }
            //如果容器没有初始化默认使用DefaultBatchConfigurer
            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;
        }

    BatchConfiure接口

    通过此接口我们可以自定义jobRepostory JobLauncher jobExplore等

    定义

    public interface BatchConfigurer {
    
        //获得jobRepository
        JobRepository getJobRepository() throws Exception;
    
        //获得事物管理器
        PlatformTransactionManager getTransactionManager() throws Exception;
    
        //获得JobLauncher
        JobLauncher getJobLauncher() throws Exception;
        
        //获得JobExplorer
        JobExplorer getJobExplorer() throws Exception;
    }

    类图

     

    BatchConfiure初始化

    spring boot项目参考自动化配置:org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration 非Spring boot项目 就参考这个类自己配置就行了

    @Configuration(
            proxyBeanMethods = false
    )
    @ConditionalOnClass({JobLauncher.class, DataSource.class})//class Path有JobLauncher.class, DataSource.class 类时
    @AutoConfigureAfter({HibernateJpaAutoConfiguration.class})
    @ConditionalOnBean({JobLauncher.class})//当容器中有JobLauncher 实现的时候
    @EnableConfigurationProperties({BatchProperties.class})//加载配置
    @Import({BatchConfigurerConfiguration.class, DatabaseInitializationDependencyConfigurer.class})//<4>BatchConfigurerConfiguration 为BatchConfigurer的自动化配置
    public class BatchAutoConfiguration {
        public BatchAutoConfiguration() {
        }
    
        /**
         * spring.batch.job.enabled 为true时 默认为true
         * JobLauncherApplicationRunner 主要作用就是实现ApplicationRunner 接口在 项目启动后自动启动job
         * @param jobLauncher
         * @param jobExplorer
         * @param jobRepository
         * @param properties
         * @return
         */
        @Bean
        @ConditionalOnMissingBean
        @ConditionalOnProperty(
                prefix = "spring.batch.job",
                name = {"enabled"},
                havingValue = "true",
                matchIfMissing = true
        )
        public JobLauncherApplicationRunner jobLauncherApplicationRunner(JobLauncher jobLauncher, JobExplorer jobExplorer, JobRepository jobRepository, BatchProperties properties) {
            JobLauncherApplicationRunner runner = new JobLauncherApplicationRunner(jobLauncher, jobExplorer, jobRepository);
            String jobNames = properties.getJob().getNames();
            if (StringUtils.hasText(jobNames)) {
                runner.setJobNames(jobNames);
            }
    
            return runner;
        }
    
        @Bean
        @ConditionalOnMissingBean({ExitCodeGenerator.class})
        public JobExecutionExitCodeGenerator jobExecutionExitCodeGenerator() {
            return new JobExecutionExitCodeGenerator();
        }
    
        /**
         * jobLauncher的容器,提供了跟丰富的方法 如停止job
         * @param jobParametersConverter
         * @param jobExplorer
         * @param jobLauncher
         * @param jobRegistry
         * @param jobRepository
         * @return
         * @throws Exception
         */
        @Bean
        @ConditionalOnMissingBean({JobOperator.class})
        public SimpleJobOperator jobOperator(ObjectProvider<JobParametersConverter> jobParametersConverter, 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);
            jobParametersConverter.ifAvailable(factory::setJobParametersConverter);
            return factory;
        }
    
        @Configuration(
                proxyBeanMethods = false
        )
        @ConditionalOnBean({DataSource.class})
        @ConditionalOnClass({DatabasePopulator.class})
        static class DataSourceInitializerConfiguration {
            DataSourceInitializerConfiguration() {
            }
    
            @Bean
            @ConditionalOnMissingBean
            BatchDataSourceInitializer batchDataSourceInitializer(DataSource dataSource, @BatchDataSource ObjectProvider<DataSource> batchDataSource, ResourceLoader resourceLoader, BatchProperties properties) {
                return new BatchDataSourceInitializer((DataSource)batchDataSource.getIfAvailable(() -> {
                    return dataSource;
                }), resourceLoader, properties);
            }
        }
    }

     <4>

    @ConditionalOnClass({PlatformTransactionManager.class})
    @ConditionalOnBean({DataSource.class})
    @ConditionalOnMissingBean({BatchConfigurer.class})
    @Configuration(
            proxyBeanMethods = false
    )
    class BatchConfigurerConfiguration {
        BatchConfigurerConfiguration() {
        }
    
        /**
         * 如果容器中存在entityManagerFactory 表示用的jpa使用JpaBatchConfigurer
         */
        @Configuration(
                proxyBeanMethods = false
        )
        @ConditionalOnClass({EntityManagerFactory.class})
        @ConditionalOnBean(
                name = {"entityManagerFactory"}
        )
        static class JpaBatchConfiguration {
            JpaBatchConfiguration() {
            }
    
            @Bean
            JpaBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, @BatchDataSource ObjectProvider<DataSource> batchDataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers, EntityManagerFactory entityManagerFactory) {
                return new JpaBatchConfigurer(properties, (DataSource)batchDataSource.getIfAvailable(() -> {
                    return dataSource;
                }), (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable(), entityManagerFactory);
            }
        }
    
        /**
         * 如果不是使用的jpa则使用BasicBatchConfigurer
         */
        @Configuration(
                proxyBeanMethods = false
        )
        @ConditionalOnMissingBean(
                name = {"entityManagerFactory"}
        )
        static class JdbcBatchConfiguration {
            JdbcBatchConfiguration() {
            }
    
            @Bean
            BasicBatchConfigurer batchConfigurer(BatchProperties properties, DataSource dataSource, @BatchDataSource ObjectProvider<DataSource> batchDataSource, ObjectProvider<TransactionManagerCustomizers> transactionManagerCustomizers) {
                return new BasicBatchConfigurer(properties, (DataSource)batchDataSource.getIfAvailable(() -> {
                    return dataSource;
                }), (TransactionManagerCustomizers)transactionManagerCustomizers.getIfAvailable());
            }
        }
    }

    BasicBatchConfigure

    public class BasicBatchConfigurer implements BatchConfigurer, InitializingBean {
        //实现了spring的InitializingBean 执行初始化
        public void afterPropertiesSet() {
            this.initialize();
        }
    
        public void initialize() {
            try {
                this.transactionManager = this.buildTransactionManager();
                this.jobRepository = this.createJobRepository();
                this.jobLauncher = this.createJobLauncher();
                this.jobExplorer = this.createJobExplorer();
            } catch (Exception var2) {
                throw new IllegalStateException("Unable to initialize Spring Batch", var2);
            }
        }
    
        protected JobExplorer createJobExplorer() throws Exception {
            PropertyMapper map = PropertyMapper.get();
            JobExplorerFactoryBean factory = new JobExplorerFactoryBean();
            factory.setDataSource(this.dataSource);
            BatchProperties.Jdbc var10001 = this.properties.getJdbc();
            var10001.getClass();
            map.from(var10001::getTablePrefix).whenHasText().to(factory::setTablePrefix);
            factory.afterPropertiesSet();
            return factory.getObject();
        }
    
        protected JobLauncher createJobLauncher() throws Exception {
            //默认SimpleJobLauncher
            SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
            jobLauncher.setJobRepository(this.getJobRepository());
            jobLauncher.afterPropertiesSet();
            return jobLauncher;
        }
    
        protected JobRepository createJobRepository() throws Exception {
            //默认使用JobRepositoryFactoryBean
            JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
            PropertyMapper map = PropertyMapper.get();
            map.from(this.dataSource).to(factory::setDataSource);
            map.from(this::determineIsolationLevel).whenNonNull().to(factory::setIsolationLevelForCreate);
            BatchProperties.Jdbc var10001 = this.properties.getJdbc();
            var10001.getClass();
            map.from(var10001::getTablePrefix).whenHasText().to(factory::setTablePrefix);
            map.from(this::getTransactionManager).to(factory::setTransactionManager);
            factory.afterPropertiesSet();
            return factory.getObject();
        }
    
        protected String determineIsolationLevel() {
            return null;
        }
        private PlatformTransactionManager buildTransactionManager() {
            PlatformTransactionManager transactionManager = this.createTransactionManager();
            if (this.transactionManagerCustomizers != null) {
                this.transactionManagerCustomizers.customize(transactionManager);
            }
    
            return transactionManager;
        }
    
        protected PlatformTransactionManager createTransactionManager() {
            return new DataSourceTransactionManager(this.dataSource);
        }
    
    }
  • 相关阅读:
    2D ARPG开发之旅(1) 贴图(tilebased)地图的实现(上)贴图修改版
    Microsoft CRM 2011 出现“无法更改域登录名" 错误
    Microsoft CRM 2011 隐藏文件菜单中的”新建活动“菜单
    Microsoft CRM 2011 安装时出现“Could not find GUID for server, Global Catalog not found in forest xxx”的问题
    C#(面向对象)
    delegate(委托)
    ww
    SQL(存储过程,触发器,回滚)
    sss
    EXcel
  • 原文地址:https://www.cnblogs.com/LQBlog/p/15434523.html
Copyright © 2020-2023  润新知