Spring @Configuration流程概述

Stella981
• 阅读 662

1. 开始

Spring核心流程梳理中我们已经介绍了,Spring的核心流程都被封装在了模板方法refresh中。

但是AnnotationConfigApplicationContext解析BeanDefinition的方式和ClassPathXmlApplicationContext还是不同。

ClassPathXmlApplicationContext是在refresh方法中通过调用prepareBeanFactory逻辑来处理。

而AnnotationConfigApplicationContext在构造逻辑中就开始处理解析BeanDefinition逻辑。

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConditionConfig.class);

从AnnotationConfigApplicationContext入口,实际解析逻辑在AnnotatedBeanDefinitionReader的doRegisterBean方法中。

主要就是解析注册BeanDefinition,包括处理@Conditional条件判断、作用域Scope、懒加载@lazy、@Primary等逻辑。

2. ConfigurationClassPostProcessor

Spring是通过BeanFactoryPostProcessor:ConfigurationClassPostProcessor来处理Configuration注解的。

我们已经知道,Spring处理BeanFactoryPostProcessor是通过refresh的invokeBeanFactoryPostProcessors方法做为入口了。

逻辑执行通过代理:PostProcessorRegistrationDelegate实现。

当然,最终的逻辑还是通过ConfigurationClassPostProcessor来执行。

其中2个重要的方法:

processConfigBeanDefinitions方法解析@Configuration的类的信息:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    // 这个时候BeanDefinition已经继续完了,所以这里可以获取容器中的所有BeanDefinition了
    
    List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    String[] candidateNames = registry.getBeanDefinitionNames();

    for (String beanName : candidateNames) {//找出容器中所有被@Configuration注解的类的BeanDefinition,包装成BeanDefinitionHolder
        if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
            configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
        }
    }

    // 处理@Order注解,根据优先级排序
    configCandidates.sort((bd1, bd2) -> {
        int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
        int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
        return Integer.compare(i1, i2);
    });

    // 通过ConfigurationClassParser解析 @Configuration 类
    ConfigurationClassParser parser = new ConfigurationClassParser(
            this.metadataReaderFactory, this.problemReporter, this.environment,
            this.resourceLoader, this.componentScanBeanNameGenerator, registry);

    // 解析@Import、@Bean等注解
    this.reader.loadBeanDefinitions(configClasses);
}

enhanceConfigurationClasses方法为Configuration设置代理类:

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
    Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
    for (String beanName : beanFactory.getBeanDefinitionNames()) {
        BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
        Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
        MethodMetadata methodMetadata = null;
   
    // 通过cglib给Configuration生成代理类逻辑
    ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
    for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
        AbstractBeanDefinition beanDef = entry.getValue();
        beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
        Class<?> configClass = beanDef.getBeanClass();
        // 最主要的方法是注册了一个BeanMethodInterceptor回调类,来处理@Bean注解
        Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
        if (configClass != enhancedClass) {
            beanDef.setBeanClass(enhancedClass);
        }
    }
}

3. 资料参考

Spring Bean生命周期

Spring核心流程梳理

点赞
收藏
评论区
推荐文章
Stella981 Stella981
3年前
Spring 操作 Redis Repositoy
Spring操作RedisRepositoy操作方式(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fsuveng.blog.csdn.net%2Farticle%2Fdetails%2F102669253%23%25
Stella981 Stella981
3年前
Spring5.0源码学习系列之Spring AOP简述(九)
前言介绍附录:Spring源码学习专栏(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fblog.csdn.net%2Fu014427391%2Fcategory_10493299.html)在前面章节的学习中,我们对Spring框架的IOC实现源码有了一定的了解,接着
Stella981 Stella981
3年前
KafkaProducer Sender 线程详解(含详细的执行流程图)
\温馨提示:本文基于Kafka2.2.1版本。上文《源码分析Kafka消息发送流程》(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fblog.csdn.net%2Fprestigeding%2Farticle%2Fdetails%2F102994716)已经详细介绍
Stella981 Stella981
3年前
Spring Bean生命周期
1\.简介在【Spring核心流程梳理】我们介绍了Spring容器的refresh过程,但是我们并没有进入到SpringBean的创建等生命周期等内容。这里,就来梳理一下SpringBean的生命周期。我们还是关注流程,重点关注核心的入口,忽略具体实现的细节。目标也很简单:1.知道SpringBean相关的扩展点
Stella981 Stella981
3年前
MapReduce的逻辑切分split与合并combiner
        在之前的博客《MapReduce中shuffle阶段概述及计算任务流程》(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fblog.csdn.net%2Fweixin_44318830%2Farticle%2Fdetails%2F103044135),小菌为大家分享了Ma
Stella981 Stella981
3年前
Spring Boot的exit code
文章目录SpringBoot的exitcode(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fblog.csdn.net%2Fsuperfjj%2Farticle%2Fdetails%2F104290745%23Spring_Bootexit_code_5)
Stella981 Stella981
3年前
Spring Boot Actuator
文章目录开始使用SpringBootActuator(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fblog.csdn.net%2Fsuperfjj%2Farticle%2Fdetails%2F104232517%23Spring_Boot_Actuator_7
Easter79 Easter79
3年前
Spring核心流程梳理
1\.简介之前其实有写过SpringBean的生命周期:Spring容器Bean与生命周期(https://my.oschina.net/u/2474629/blog/3024794)。当时太过于关注细节的实现,而进入了Spring庞大的体系之中,对于还不太了解Spring的朋友不太友好,也不方便记忆。所以,这一次以应用为
Stella981 Stella981
3年前
Spring Annotation 启动流程
SpringAnnotation启动流程本文将对Spring注解方式的启动流程进行分析author:huifer(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fhuifer)实例
Easter79 Easter79
3年前
Spring完整版(三)
Spring完整版(三)七、Bean的自动装配(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fblog.csdn.net%2Fweixin_46990523%2Farticle%2Fdetails%2F109220044%23Bean_1)7.1