spring batch @EnableBatchProcessing注解源码分析

https://docs.spring.io/spring-batch/4.2.x/reference/html/job.html#configuringJobRepository

在上述链接中的小节Configuring a JobRepository , 有一段话
When using @EnableBatchProcessing, a JobRepository is provided out of the box for you. This section addresses configuring your own As described in earlier, the JobRepository is used for basic CRUD operations of the various persisted domain objects within Spring Batch, such as JobExecution and StepExecution. It is required by many of the major framework features, such as the JobLauncher, Job, and Step. When using java configuration, a JobRepository is provided for you. A JDBC based one is provided out of the box if a DataSource is provided, the Map based one if not. However you can customize the configuration of the JobRepository via an implementation of the BatchConfigurer interface.. (使用@EnableBatchProcessing注解,spring batch为你提供了开箱即用的JobRepository 。如前所述,JobRepository用于Spring Batch中各种持久化域对象的基本CRUD操作,例如JobExecution和StepExecution。 许多主要框架功能(例如JobLauncher,Job和Step)都需要它。 使用Java配置时,会为您提供JobRepository。 如果提供了数据源,则开箱即用地提供基于JDBC的数据库,否则不提供基于Map的数据库。 但是,您可以通过BatchConfigurer接口的实现来自定义JobRepository的配置。)
大致的意思,使用了@EnableBatchProcessing注解,无需实现BatchConfigurer接口来自定义JobRepository的相关配置,就能使用JobRepository进行开发。

一、开始之前,先介绍spring的一个知识点。

1、@Import注解,和xml配置的 <import />标签作用一样,允许通过它引入 @Configuration 注解的类 (java config),
2、@Import 的实现很多时候需要借助 ImportSelector 接口, 需要通过这个接口的实现类去决定要引入哪些 @Configuration。
3、Springboot 对@Import注解的处理过程,发生在

AbstractApplicationContext.refresh() 
-> AbstractApplicationContext.invokeBeanFactoryPostProcessors(beanFactory)
->PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) 
->ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 
-> ConfigurationClassPostProcessor.processConfigBeanDefinitions(BeanDefinitionRegistry registry)

1、 springboot初始化的普通context(非web) 是AnnotationConfigApplicationContext(spring注解容器) 在初始化的时候会初始化两个工具类, AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner 分别用来从 annotation driven 的配置和xml的配置中读取beanDefinition并向context注册, 那么在初始化 AnnotatedBeanDefinitionReader 的时候, 会向BeanFactory注册一个ConfigurationClassPostProcessor 用来处理所有的基于annotation的bean, 这个ConfigurationClassPostProcessor 是 BeanFactoryPostProcessor 的一个实现,springboot会保证在 invokeBeanFactoryPostProcessors(beanFactory) 方法中调用注册到它上边的所有的BeanFactoryPostProcessor 因此,在spring容器启动时,会调用ConfigurationClassPostProcessor .postProcessBeanDefinitionRegistry()方法。
4、ConfigurationClassParser, 在ConfigurationClassPostProcessor .postProcessBeanDefinitionRegistry()方法中实例化ConfigurationClassParser调用

// Parse each @Configuration class
        ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);

那么在 ConfigurationClassParser -> processConfigurationClass() -> doProcessConfigurationClass() 方法中我们找到了 (这里边的流程还是很清楚的, 分别按次序处理了@PropertySource, @ComponentScan, @Import, @ImportResource, 在处理这些注解的时候是通过递归处理来保证所有的都被处理了)
取重点代码段

// Process any @Import annotations
        processImports(configClass, sourceClass, getImports(sourceClass), true);

processImports流程如下: •首先,判断如果被import的是 ImportSelector.class 接口的实现, 那么初始化这个被Import的类, 然后调用它的selectImports方法去获得所需要的引入的configuration, 然后递归处理 •其次,判断如果被import的是 ImportBeanDefinitionRegistrar 接口的实现, 那么初始化后将对当前对象的处理委托给这个ImportBeanDefinitionRegistrar (不是特别明白, 只是我的猜测) •最后, 将import引入的类作为一个正常的类来处理 ( 调用最外层的doProcessConfigurationClass())

综上, 如果引入的是一个正常的component, 那么会作为@Component或者@Configuration来处理, 这样在BeanFactory里边可以通过getBean拿到, 但如果你是 ImportSelector 或者 ImportBeanDefinitionRegistrar 接口的实现, 那么spring并不会将他们注册到beanFactory中,而只是调用他们的方法。

二、正题,根据@EnableBatchProcessing注解类的注释,找到BatchConfigurer接口的实现类

进入注解@EnableBatchProcessing, 注解类的注解有@Import(BatchConfigurationSelector.class),可知,导入了BatchConfigurationSelector类。 接下来进入BatchConfigurationSelector类分析

代码略
BatchConfigurationSelector类实现了ImportSelector接口,
Base Configuration class providing common structure for enabling and using Spring Batch. Customization is available by implementing the BatchConfigurer interface (基本配置类提供了用于启用和使用Spring Batch的通用结构。 通过实现BatchConfigurer接口可以进行自定义)
从注释可以了解到,通过@Import(BatchConfigurationSelector.class),可将BatchConfigurer接口的实现类(被@Configuration注解),查找后注入到spring IOC容器中。

BatchConfigurationSelector实现了接口ImportSelector的方法selectImports(),从该方法可知,会返回ModularBatchConfiguration、SimpleBatchConfiguration。因EnableBatchProcessing注解类中明确说了Modular=false,因此,默认返回SimpleBatchConfiguration类的全限定名。默认情境,这个类就是@EnableBatchProcessing注解要引入的功能,

进入SimpleBatchConfiguration类,被@Configuration注解。查看该类的继承关系,只继承了AbstractBatchConfiguration,并没有实现@EnableBatchProcessing注释中说的BatchConfigurer接口,难道没有进行JobRepository的相关配置。再找找,,,在AbstractBatchConfiguration抽象类中,看到了BatchConfigurer的使用。并不是通过接口方式实现BatchConfigurer来进行JobRepository的配置。而是运用组合关系,在AbstractBatchConfiguration中,实例化DefaultBatchConfigurer,该类实现了接口BatchConfigurer。通过DefaultBatchConfigurer进行JobRepository的相关配置。

三、何时调用ImportBatchConfigurationSelector的实现接口方法selectImports(),从而找到SimpleBatchConfiguration

从之前补充的知识点可知,触发位置在
ConfigurationClassParser -> processConfigurationClass() -> doProcessConfigurationClass() doProcessConfigurationClass()内的重点代码 processImports(configClass, sourceClass, getImports(sourceClass), true);

processImports方法内,统一处理所有@Import引入的类,在该方法内,会进行 *.selectImports()调用。将返回值存入List<sourceClass> annotatedClass , 后续spring的处理,会扫描该list,将配置类注入到spring IOC容器中。
在processImports方法,也可以印证之前的观点,@Import引入的类,如果被@Component、@Configuration注解,且未实现ImportSelector接口,在spring容器中(BeanFactory),可以通过getBean拿到,但实现了 ImportSelector 或者 ImportBeanDefinitionRegistrar 接口,spring并不会将它们注入到容器中,而是只调用它们的方法selectImports()。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,924评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,781评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,813评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,264评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,273评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,383评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,800评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,482评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,673评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,497评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,545评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,240评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,802评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,866评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,101评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,673评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,245评论 2 341

推荐阅读更多精彩内容

  • @Enable** 注解,一般用于开启某一类功能。类似于一种开关,只有加了这个注解,才能使用某些功能。 sprin...
    zeody阅读 472评论 0 1
  • 本来是准备看一看Spring源码的。然后在知乎上看到来一个帖子,说有一群**自己连Spring官方文档都没有完全读...
    此鱼不得水阅读 6,925评论 4 21
  • 概述 Spring是什么? Spring是一个开源框架,为了解决企业应用开发的复杂性而创建的,但是现在已经不止于企...
    琅筑阅读 1,147评论 2 8
  • 25个经典的Spring面试问答 本人收集了一些在大家在面试时被经常问及的关于Spring的主要问题,这些问题有可...
    杀小贼阅读 682评论 0 2
  • 前言 上一篇写了Spring相关的注解,由于我的源码分析主要采用的是Springboot的方式,所以这里也顺便把s...
    阿亮私语阅读 1,294评论 0 2