@Configuration 注解的原理


前言

  在使用SpringBoot的时候,如果想定义一个配置类就可以使用@Configuration注解,并且在@Configuration注解的类中可以通过@Bean注解来完成Bean注入到Spring容器中。那么SpringBoot是什么时候读取@Configuration注解并将注解修饰的类中的Bean加载到容器中的呢。


一、Bean是什么时候加载到SpringBoot容器中的?

  SpringBoot容器在启动的时候会先将所有需要交给Spring管理的Bean创建为BeanDefinition,并将这些BeanDefinition注册到注册表中。而SpringBoot中的一个扩展点BeanFactoryPostProcessor正是完成读取Bean的配置,并创建为BeanDefinition对象,并将所有创建的BeanDefinition注册到注册表中。

  扩展点BeanFactoryPostProcessor都是在什么时候执行的能,进入AbstractApplicationContext的refresh方法中,这个方法中完成了SpringBoot在启动过程中所需要完成的一些非常重要的方法,比如执行一些扩展点(BeanFactoryPostProcessor、BeanPostProcessor、Listenter等)、实例化Bean、初始化Bean等。其中的invokeBeanFactoryPostProcessors方法就是完成了执行所有BeanFactoryPostProcessor扩展点的操作。前面说到的BeanDefinition一般都是由BeanFactoryPostProcessor扩展点去加载的,所以我们看这个方法是否有读取@Configration注解所配置的Bean。

可以看到最终需要执行的扩展点类为ConfigurationClassPostProcessor 。这里直接公布答案,SpringBoot正是通过ConfigurationClassPostProcessor 来加载@Configuration注解并解析其中的@Bean注解,然后将Bean加载到Spring容器中的。

二、ConfigurationClassPostProcessor的原理

1.方法执行的顺序 

  

  ConfigurationClassPostProcessor 实现了BeanDefinitionRegistryPostProcessor,由此可知,首先会执行ConfigurationClassPostProcessor 的postProcessBeanDefinitionRegistry方法,进入方法后查看方法的调用链。最终会执行processConfigBeanDefinitions方法

这个方法中会读取有@Configuration注解的类,并加入到configCandidates中,可以进入checkConfigurationClassCandidate方法中,其中的判断是否有@Configuratin注解的逻辑就在这个里面。当前这个测试项目中只有Application的启动类才有@Configuratin注解。

 

然后下面就到了加载@Configuration注解的类中的配置的逻辑了。

2.ConfigurationClassParser

  看上面的代码,先创建了ConfigurationClassParser对象,然后调用对象的pase方法,我们来看一下这个pase方法中都做了哪些操作。进入方法可以看到,parse中调用了processConfigurationClass方法,processConfigurationClass方法中又调用了doProcessConfigurationClass方法,这个方法是主要逻辑所在的方法,直接跳入到这个方法中。

@Nullable
    protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter) throws IOException {

// 加载Component注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
            this.processMemberClasses(configClass, sourceClass, filter);
        }

// 加载PropertySource注解

        Iterator var4 = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class).iterator();

.....
.....

// 加载ComponentScan注解
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

.....
.....
// 加载Import注解
this.processImports(configClass, sourceClass, this.getImports(sourceClass), filter, true);

// 加载ImportResource注解
        importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);


}

这里解析了@Configuration下的所有指定的注解,同时也解释了SpringBoot中一些其他的注解的读取时间和原理,例如@Import注解等。创建完parser之后,会创建reader来读取配置信息,进入ConfigurationClassBeanDefinitionReader的loadBeanDefinition方法中

直接进入解析@Configuration注解的逻辑方法中

 

可以看到,这里面读取了@Bean注解,并将其创建为BeanDifinition对象,并注册到注册表中。 

总结

本篇文章通过源码分析了@Configuretion注解的实现原理。其实SpringBoot中关于IOC、AOP等实现的原理一般都是基于Spring的各个扩展点,大多数是BeanFactoryPostProcessor、BeanPostPricessor等,可以通过熟悉和理解SpringBoot的扩展点,以及各个扩展点执行的时间,这样可以更好的让我们去理解SpringBoot的原理

  • 12
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值