天天看点

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

  一名劫匪慌忙中窜上了一辆车的后座,上车后发现主驾和副驾的一男一女疑惑地回头看着他

  他立即拔出枪威胁到:“赶快开车,甩掉后面的警车,否则老子一枪崩了你!”

  于是副驾上的男人转过脸对那女的说:“大姐,别慌,听我口令把刚才的动作再练习一遍,挂一档,轻松离合,轻踩油门,走...走,哎 走...哎,哎,对,走走...

  最后,三人都躺到了医院,劫匪的手上还戴上了铐子...

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

劫匪的内心

  估摸着大家已经忘记了createApplicationContext的内容,本文不做过多的回顾,只是提醒大家:在AnnotationConfigServletWebServerApplicationContext的实例化过程中,实例化了AnnotatedBeanDefinitionReader,另外也将ConfigurationClassPostProcessor定义注册到了beanFactory中,如下图所示

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

  看着AnnotatedBeanDefinitionReader、ConfigurationClassPostProcessor是不是隐约感觉到了什么? ConfigurationClassPostProcessor实现了BeanDefinitionRegistryPostProcessor,BeanDefinitionRegistryPostProcessor又实现了BeanFactoryPostProcessor,关于BeanFactoryPostProcessor,大家可以看看这篇文章:Spring拓展接口之BeanFactoryPostProcessor,占位符与敏感信息解密原理

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional
spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

View Code

    @Configuration能够修饰Class、interface和enum,用的最多的还是标注在类上,相当于把该类作为spring的xml配置文件中的<beans>,用于配置spring容器;@Configuration往往会结合@Bean来使用,@Bean等价于spring的xml配置文件中的<bean>,用于注册bean对象。@Configuration和@Bean组成了基于java类的配置,是spring的推荐配置方式。最简单的使用如下

    如上代码就会在spring容器中注册一个名叫mycat的Cat类型的Bean

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional
spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    Spring的条件化配置,当我们向spring注册bean时,可以对这个bean添加一定的自定义条件,当满足这个条件时注册这个bean,否则不注册。springboot中部分实现子类如下

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    springboot更多实现请查看org.springframework.boot.autoconfigure.condition包。Condition一般配合@Conditional使用,更多信息往下看

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional
spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    Spring的条件注解,其value是一个Class<? extends Condition>[],只有数组中的全部Condition全部匹配成功时,被@Conditional修饰的组件才会被注册到Spring容器中。@Conditional只是一个标志,标示需要进行条件判断,而具体的判断规则则由具体的Condition来实现。

    在SpringBoot源码中很容易看到被@Conditional注解的组合注解,例如:@ConditionalOnBean、@ConditionalOnMissingBean、@ConditionalOnClass、@ConditionalOnMissingClass等,具体如下

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    springboot还提供了AutoConfigureAfter、AutoConfigureBefore、AutoConfigureOrder,看名字基本知道其作用,具体细节需要大家自己去跟了。

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    接口都能访问通,数据返回也都正确,非常完美

    完整工程代码:spring-boot-condition

    当我们把MyConfiguration中的myCat方法注释掉(ConditionWeb中的cat相关也注释掉),再启动应用的时候,应用报错启动不起来,提示如下信息:

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional
spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    ConditionWeb中需要Dog类型的bean,而Dog实例化又依赖Cat实例,而我们没有实例化Cat,所以应用启动报错,提示如上信息 

  我们要探究什么了?不探究太细,就探究@Configuration修饰的配置类是何时解析的,@Conditional是何时生效、如何生效的

    ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor(可以查看ConfigurationClassPostProcessor的类继承结构图),那么我们从AbstractApplicationContext的refresh方法调用的invokeBeanFactoryPostProcessors(beanFactory)方法开始

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    来到了processConfigurationClass方法,其详细代码如下

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional
spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    其中shouldSkip方法如下

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional
spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    我们再回过头去看processConfigBeanDefinitions方法

spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional
spring-boot-2.0.3源码篇 - @Configuration、Condition与@Conditional

    这个问题再上面已经全部得到体现,Spring不会无脑的加载所有的@Configuration class,只会加载满足条件的@Configuration class,而@Conditional就是条件标志,至于条件匹配规则这由Condition提供;shouldSkip方法中用到Conditional和Condition,完成条件的匹配处理。

  1、@Configuration和@Bean组成了基于java类的配置,与xml中的<Beans>、<Bean>功能一致,Spring推荐java类的配置;

  2、Condition与@Conditional实现了条件配置,只有满足了条件的@Configuration class和@Bean才会被注册到Spring容器;

  3、Spring以我们的应用启动类为基础来递归扫描配置类,包括我们应用中的配置类、Spring自己的以及第三方的配置类(springboot集成的各种配置类(spring-boot-autoconfigure-xxx.RELEASE.jar下的spring.factories文件中的Auto Configure),还有pageHelper的自动配置,等等);前提是需要开启自动配置(@EnableAutoConfiguration)。

  SpringBoot源码分析之条件注解的底层实现

  Spring 工具类 ConfigurationClassParser 分析得得到配置类

继续阅读