Spring源码解析系列一:配置类的初始化过程

从今天开始,准备写关于Spring源码的博客,那么废话不多说, 咱们开始搞!

1.环境准备

1).看图:

1.png

PersonService类:

@Component
public class PersonService {
    public void run(){
        System.out.println("run方法执行了");
    }
}

SpringConfiguration类:

@ComponentScan("my.blog")
public class SpringConfiguration {

}

Test01类:

public class Test01 {
    public static void main(String[] args) {
        //这个构造方法会把Spring所有的环境都准备好
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        PersonService person = ac.getBean(PersonService.class);
        person.run();
    }
}

2.介绍:注解配置应用上下文

AnnotationConfigApplicationContext 顾名思义:注解配置应用上下文, 我在演示当中使用的是注解的方式

所以需要 new AnnotationConfigApplicationContext 这个对象.

如果采用的是xml的配置方式 则需要 new ClassPathXmlApplicationContext ,这个应该我不用多说,我想你应该懂的!

那么这个实例化对象的过程,Spring到底中干了哪些见不得人的事呢? 接下来跟着我一起去揭开他的神秘面纱!

我们点击 new AnnotationConfigApplicationContext看一下他的构造方法:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
        //这个类有父类,所以会先初始化父类的构造方法,接着初始化自己的构造方法

        //调用无参构造方法进行初始化一个读取器和扫描仪
        this();
        
       //这个方法的作用:主要是把配置类的信息加载进工厂中
       //在这里需要你记住一个类:DefaultListableBeanFactory,后面会非常的重要
        register(annotatedClasses);

        //实例化所有被加了组件的对象
        refresh();
    }

我们发现这个构造函数的参数可以一次性传多个配置类,后面代码中其实会遍历annotatedClasses 这个数组

我们看一下 this() 干了哪些事?

    public AnnotationConfigApplicationContext() {
        //这里也会先初始化父类的构造方法
        
        //创建一个读取被加了注解的bean读取器 ,这个读取器到底什么鬼,不是这节的重点,可以先忽略
        //你就知道他创建了一个读取器就完事了
        this.reader = new AnnotatedBeanDefinitionReader(this);
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }

我们回到 register(annotatedClasses);这个方法, 这个方法就是本节的大哥,我们现在就要去看看,他为Spring干了哪些脏活!

3.加载配置类

我们点击 register(annotatedClasses)

2.png

嗯....,好像没啥用!

点击 this.reader.register(annotatedClasses); 方法

3.png

这时候,我们发现这个方法开始遍历annotatedClasses 数组,由此我们可以一次性写多个配置文件传给构造方法的

开始遍历annotatedClasses(注意:本次演示中,我只添加了一个配置类), 调用 registerBean(annotatedClass);

我们这时候点击 registerBean(annotatedClass);

4.png

点击 doRegisterBean(annotatedClass, null, null, null);

    <T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
            @Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
        //(1)(解析:查看下面图)
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
     
        
        //这个不是重点,跳过
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }
        
         //这个不是重点,跳过 instanceSupplier为null值
        abd.setInstanceSupplier(instanceSupplier);

        //(2)得到类的作用域 单例还是多例(解析:查看下面图)
        ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
        
        //把类的作用域赋值给AnnotatedGenericBeanDefinition对象
        abd.setScope(scopeMetadata.getScopeName());

        //生成配置类的名称,如果@Component没有对应的名称   (我没有加名称)
        //默认是类的小驼峰式命名称 (所有此时beanName为springConfiguration)
        String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

        /**
         * (3)把AnnotatedGenericBeanDefinition对象传进
         * 然后获取获取元数据metadata对象,判断元数据对象中是否存在lazy,DependsOn,Primary Role 等注解
         * 如果有这些注解,则在AnnotatedGenericBeanDefinition对象中记录
         */
        AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

        //qualifiers本身传过来的就是一个 null 值
        //如果不手动传,永远为空值,没有意义
        if (qualifiers != null) {
            for (Class<? extends Annotation> qualifier : qualifiers) {
                if (Primary.class == qualifier) {
                    abd.setPrimary(true);
                }
                else if (Lazy.class == qualifier) {
                    abd.setLazyInit(true);
                }
                else {
                    abd.addQualifier(new AutowireCandidateQualifier(qualifier));
                }
            }
        }
        
        //这个不是重点
        for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
            customizer.customize(abd);
        }
        
         //(4)把abd放进去,赋值给了成员变量beanDefinition
        //把BeanName赋值进去,可以说是增强版的abd对象
        //查看后面的代码发现,其实definitionHolder就只是起到一个临时容器的作用
        BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

        //这个比较复杂,以后可以讲 和本节无关
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);

        //(5)现在又把增强版的 definitionHolder 放到registry这个容器中
        //BeanDefinitionRegistry 顾名思义 就是注册BeanDefinition的
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }

1).我们查看代码AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);干了哪些事 ?

通过debug 查看 abd 对象内容

5.png

总结:

  1. 根据指定的配置类,创建一个GenericBeanDefinition对象
  2. 这个GenericBeanDefinition对象包含了该类的一些元信息,例如注解信息: scope,lazy,ComponentScan等注解
  3. 这些注解存储在 GenericBeanDefinition中的 元数据(metadata)对象中
  4. 元数据对象有一个注解集合 annotations ,存储所有的注解信息

2).接下来查看 ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);

6.png

执行完这个abd.setScope(scopeMetadata.getScopeName());方法后

7.png

3).查看 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

点击进入

8.png

额..., 这个方法好像也没啥...

把传进的abd对象拆开,又传了abd对象和abd.getMetadata()元数据对象

点击 processCommonDefinitionAnnotations(abd, abd.getMetadata());

    static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
        //判断当前的类是否加了lazy注解
        AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
        
        //如果不为null,则把AnnotatedBeanDefinition中的 lazyInit 默认的false 修改为true
        if (lazy != null) {
            abd.setLazyInit(lazy.getBoolean("value"));
        }
        else if (abd.getMetadata() != metadata) {
            lazy = attributesFor(abd.getMetadata(), Lazy.class);
            if (lazy != null) {
                abd.setLazyInit(lazy.getBoolean("value"));
            }
        }
        
        //判断元数据对象中时候有@Primary,默认时候primary是 false ,如果有则该为true
        if (metadata.isAnnotated(Primary.class.getName())) {
            abd.setPrimary(true);
        }
        
        //判断时候有@DependsOn注解
        AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
        if (dependsOn != null) {
            abd.setDependsOn(dependsOn.getStringArray("value"));
        }

        //判断时候有@Role注解
        AnnotationAttributes role = attributesFor(metadata, Role.class);
        if (role != null) {
            abd.setRole(role.getNumber("value").intValue());
        }
        
        //判断时候有@Description注解
        AnnotationAttributes description = attributesFor(metadata, Description.class);
        if (description != null) {
            abd.setDescription(description.getString("value"));
        }
    }

总结:

  1. 把AnnotatedGenericBeanDefinition对象传进去
  2. 获取元数据metdata对象,判断元数据对象中是否存在lazy,DependsOn,Primary Role 等注解
  3. 如果有这些注解,则在AnnotatedGenericBeanDefinition对象中记录

4).查看 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);

debug 发现

9.png

5).查看 BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

点击进入

public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        
        //在这里又获取beanName的名称
        String beanName = definitionHolder.getBeanName();
    
        //现在把definitionHolder拆分了,又把abd对象拿出来了
        //似乎definitionHolder就只是封装了一下,然后又给拆分, 可以理解为一个临时的容器
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

         //这个不重要,spring当中处理别名的
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
    }

我们点击 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

发现是一个接口, 按住快捷键 Ctrl + Alt + B ,有三个实现类,前面就你留意的 DefaultListableBeanFactory 在这里出现了,

选择 DefaultListableBeanFactory

10.png
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
   //-------------------------------------------------------------------------------
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
     
        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }
        //查看该bean时候在map集合中存储过
        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            else if (existingDefinition.getRole() < beanDefinition.getRole()) {
                // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
                if (logger.isInfoEnabled()) {
                    logger.info("Overriding user-defined bean definition for bean '" + beanName +
                            "' with a framework-generated bean definition: replacing [" +
                            existingDefinition + "] with [" + beanDefinition + "]");
                }
            }
            else if (!beanDefinition.equals(existingDefinition)) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Overriding bean definition for bean '" + beanName +
                            "' with a different definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            else {
                if (logger.isTraceEnabled()) {
                    logger.trace("Overriding bean definition for bean '" + beanName +
                            "' with an equivalent definition: replacing [" + existingDefinition +
                            "] with [" + beanDefinition + "]");
                }
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                }
            }
     //---------------------------------------------------------------------------------------
            //前面的代码都是一些判断,验证不是重点
            //重点是这里的代码,前方高能
            else {
                //在这个方法中就把 beanDefinition 存储在 DefaultListableBeanFactory的map集合中
                //顾名思义,beanDefinitionMap就是一个存储beanDefinition的map集合
                //在这个集合当中还有Spring当中本身已经初始好的对象
                this.beanDefinitionMap.put(beanName, beanDefinition);
                //把beanName存储在这个list集合中
                this.beanDefinitionNames.add(beanName);
                //这个是去重的,不是重点
                removeManualSingletonName(beanName);
            }
            this.frozenBeanDefinitionNames = null;
        }

        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
    }

this.beanDefinitionMap.put(beanName, beanDefinition); 之前

11.png

this.beanDefinitionMap.put(beanName, beanDefinition); 之后

12.png

this.beanDefinitionNames.add(beanName); 之前

13.png

this.beanDefinitionNames.add(beanName); 之后

14.png

整个配置类的加载过程就执行完了,最后总结一下 register(annotatedClasses); 都干了哪些事?

  1. 加载配置类的元数据 AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
  2. 给abd对象设置作用域
  3. 遍历元数据注解 ,判断时候存在某注解
  4. 把配置类信息对象存储到 DefaultListableBeanFactory的beanDefinitionMap集合中
  5. 把配置类的名称存储到 DefaultListableBeanFactory的 beanDefinitionNames 集合中

4.视频讲解:

<https://www.bilibili.com/video/av67899876?p=2>

视频为自己学习的时候录制的,也方便自己以后看

Spring5源码地址:

<https://gitee.com/zouchangfu/spring_5_source_code>

Spring5源码都是已经构建好的了,无需再使用gradle进行构建了,直接打开就可以跑起来

写在最后:

大二学生一枚,挤时间写博客不容易,看完顺手点个赞,你的点赞是对我最大的鼓励

当你跟别人讨论技术,发现自己对不上话的时候,你会后悔自己没有努力的!

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

推荐阅读更多精彩内容