Spring ioC源码深入剖析Bean的实例化

 2022-09-11
原文地址:https://blog.51cto.com/u_14693305/5357831

1 Spring源码阅读技巧

目标:学习阅读源码的技巧(理论+idea)
(重要)源码阅读七大原则:
1、不要一个类一个类的去看
2、更不要一行一行的去看(重点)
3、看不懂的先不看
4、只看核心接口(下面会讲到核心接口)和核心代码(do开头)
5、根据语义和返回值去看
6、ioc (父子容器----对应-父类子类)上下看、带着问题(目标)去看
7、灵活使用工具,将事半功倍(学会看类图ctrl+alt+shift+u、学会看类继承关系ctr+h;方法调用栈+查
ctr+shift+f
阅读源码目的
看设计思想!!!
总结:
1、通过理论中的技巧去阅读
2、通过idea自带的功能去辅助阅读

2 ioC初始化流程与继承关系

引言
在看源码之前需要掌握Spring的继承关系和初始化

  1. ioC容器初始化流程
    目标:
    1、ioC容器初始化过程中到底都做了哪些事情(宏观目标)
    2、ioC容器初始化是如何实例化Bean的(划重点,最终目标)
    //没有Spring之前我们是这样的
    User user=new User();
    user.xxx();
    //有了Spring之后我们是这样的
    <bean id="userService" class="com.spring.test.impl.UserServiceImpl">
    User user= context.getBean("xxx");
    user.xxx();

ioC流程简化图(七大阶段):
tips:
下面的流转记不住没有关系
在剖析源码的整个过程中,我们一直会拿着这个图和源码对照

202209112138392741.png
初始化:
1、容器环境的初始化
2、Bean工厂的初始化(ioC容器启动首先会销毁旧工厂、旧Bean、创建新的工厂)

读取与定义
读取:通过BeanDefinitonReader读取我们项目中的配置(application.xml)

定义:通过解析xml文件内容,将里面的Bean解析成BeanDefinition(未实例化、未初始化)实例化与销毁Bean实例化、初始化(注入)销毁缓存等

扩展点
事件与多播、后置处理器
复杂的流程学会划重点:

202209112138408122.png
重点总结:
1、工厂初始化过程
2、解析xml到BeanDefinition,放到map
3、调用后置处理器
4、从map取出进行实例化( ctor.newInstance)
5、实例化后放到一级缓存(工厂)

  1. 容器与工厂继承关系
    tips:
    下面的继承记不住没有关系
    在剖析源码的整个过程中,我们一直会拿着这个图和源码对照

目标:简单理解ioC容器继承关系

202209112138419253.png
继承关系理解:
1、ClassPathXmlApplicationContext最终还是到了 ApplicationContext 接口,同样的,我们也可以
使用绿颜色的 FileSystemXmlApplicationContext 和 AnnotationConfigApplicationContext 这两个类 完成容器初始化的工作

2、FileSystemXmlApplicationContext 的构造函数需要一个 xml 配置文件在系统中的路径,其他和
ClassPathXmlApplicationContext 基本上一样

Bean工厂继承关系
目标:1、简单理解Bean工厂继承关系
2、ioc容器与Bean工厂关系?

202209112138431374.png

  1. ApplicationContext 继承了 ListableBeanFactory,这个Listable 的意思就是,通过这个接口, 我们可以获取多个 Bean最顶层 BeanFactory 接口的方法都是获取单个 Bean 的。
  2. ApplicationContext 继承了 HierarchicalBeanFactory,获取bean工厂关系.,HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个Bean 有可能有父
    Bean
  3. AutowireCapableBeanFactory 这个名字中的 Autowire 大家都非常熟悉,它就是用来自动装配
    Bean 用的,但是仔细看上图,ApplicationContext 并没有继承它,不过不用担心,不使用继承, 不代表不可以使用组合,如果你看到 ApplicationContext 接口定义中的最后一个方法getAutowireCapableBeanFactory() 就知道了。
  4. ConfigurableListableBeanFactory 也是一个特殊的接口,看图,特殊之处在于它继承了第二层
    所有的三个接口,而 ApplicationContext 没有。这点之后会用到。

总结:上面的继承关系不用刻意去记住它
我们再学习的源码的时候,遇到哪个类,可以和这个图对照

3 Bean是怎么实例化的

引言:
接下来,我们就正式讲解Spring ioC容器的源码
首先,我们要带着问题和目的去阅读;
比如,我们平时玩魔方,
魔方一共6个面,只要我们最终能每个面的颜色弄成一样的就算完成了这就是目的
读源码也是一样的,带着问题、有目的的就看
我们的目的很简单,就是看一下ioC如何帮我们生成对象的

3.1 找到 ioC源码的入口

目标:找到ioC源码的入口
测试代码:进入到Spring源码入口

    package com.spring.test;
    import com.spring.test.pojo.Person;
    import com.spring.test.service.UserService;
    import org.springframework.context.ApplicationContext;
    import
    org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.context.support.FileSystemXmlApplicationContext;
    //宏观目标:ioC初始化到底做了哪些事情?
    public class Main {
    public static void main(String[] args) {
    //1、使用注解
    //AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Object.class);
    //2、使用FileSystemXmlApplicationContext
    // ApplicationContext context =new FileSystemXmlApplicationContext("classpath*:application.xml");
    ///3、使用ClassPathXmlApplicationContext
    ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:application.xml");
    // (c)从容器中取出Bean的实例,call:
    AbstractApplicationContext.getBean(java.lang.Class<T>)
    //工厂模式(simple)
    UserService userService = context.getBean(UserService.class);
    // 这句将输出: hello world
    System.out.println(userService.getName());
       }
    }

进入到ClassPathXmlApplicationContext的有参构造器

org.springframework.context.support.ClassPathXmlApplicationContext#ClassPathXmlApplication Context(java.lang.String[], boolean, org.springframework.context.ApplicationContext)

    public ClassPathXmlApplicationContext(
    String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
    throws BeansException {
    //继承结构图
    //1、返回一个classloader
    //2、返回一个解析器
    super(parent);
    // 1、获取环境(系统环境、jvm环境)
    // 2、设置Placeholder占位符解析器
    // 2、将xml的路径解析完存储到数组
    setConfigLocations(configLocations);
    //默认为true
    if (refresh) {
    //核心方法(模板)
    refresh();
       }
    }

重点步骤解析(断点跟踪讲解)
super方法做了哪些事情
1、super方法:通过点查看父容器与子容器概念
2、super方法:调用到顶端,一共5层,每一层都要与讲义中的【ioC与Bean工厂类关系继承】进行对照
3、super方法:在什么地方初始化的类加载器和解析器
setConfigLocations方法做了哪些事情:
1、如何返回的系统环境和jvm环境
2、路径的解析
3、设置占位符解析器进入核心方法refresh

4 容器13大模板方法实例化bean

4.1 容器13大模板方法之一:prepareRefresh()

目标:prepareRefresh()到底做了哪些事情
prepareRefresh()【准备刷新】

    // synchronized块锁(monitorenter --monitorexit),不然 refresh() 还没结束,
    又来个启动或销毁容器的操作
    synchronized (this.startupShutdownMonitor) {
    //1、【准备刷新】【Did four things】
    prepareRefresh();
    ......。略

1、为什么要加快锁synchronized
2、prepareRefresh干了哪些事情
1、记录启动时间/设置开始标志
2、子类属性扩展(模板方法)
3、校验xml配置文件
4、初始化早期发布的应用程序事件对象(不重要,仅仅是创建setg对象)

4.2 容器13大模板方法之二:obtainFreshBeanFactory()

obtainFreshBeanFactory【获得新的bean工厂】
最终目的就是解析xml,注册bean定义(架构图)(重要)为什么要注册bean定义?

项目中,配置bean(包含但不限于)或者aop的时候,我们可以使用xml
也可以使用注解,所以,在正式的实例化前;先把解析xml(或注解)成bean定义后续,实例化的时候,直接从bean定义去拿

    // 2、【获得新的bean工厂】关键步骤
    //1、关闭旧的 BeanFactory
    //2、创建新的 BeanFactory(DefaluListbaleBeanFactory)
    //3、解析xml/加载 Bean 定义、注册 Bean定义到beanFactory(未初始化)
    //4、返回全新的工厂
    ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();
    refreshBeanFactory方法
    //1、关闭旧的 BeanFactory
    createBeanFactory();方法
    //2、创建新的 BeanFactory(DefaluListbaleBeanFactory)
    此处解释spring为什么创建DefaultListableBeanFactory?
    原来所说的bean工厂就是DefaultListableBeanFactory
    //*****************此处需要了解 BeanDefinition类具体干了哪些事情
    *************************
    loadBeanDefinitions(beanFactory);方法
      // 非常重要,目标如下
    // 1、通过BeanDefinitionReade解析xml为Document
    // 2、将Document注册到BeanFactory 中(未初始化),
    // 经历21个方法;在DefaultListableBeanFactory.registerBeanDefinition注册
    的
    //一直都有loadBeanDefinitions方法,直到看到doLoadBeanDefinition
    //3、解析xml/加载 Bean 定义、注册 Bean定义到beanFactory(未初始化)
    找到到核心方法doLoadBeanDefinitions
    //进入,将Document注册到BeanFactory
    documentReader.registerBeanDefinitions(doc,
    createReaderContext(resource));
    将当前资源文件转换成DOM树(registerBeanDefinitions(doc, resource)方法)
    //核心,将xml转成的Document注册到BeanFactory
    doRegisterBeanDefinitions(root);
    //4、返回全新的工厂
    这个全新的工厂包含了bean定义以及各种解析器

ps:上面的核心代码由于loadBeanDefinitions做完事情需要经历19个方法,通过断点,介绍核心的
知识点
当前阶段最重要的就是读取xml,然后将xml注册到bean工厂
org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
代码如下

    else {
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    // 将 BeanDefinition 放到这个 map 中,这个 map 保存了所有的
    BeanDefinition
    this.beanDefinitionMap.put(beanName, beanDefinition);
    // 这是个 ArrayList,所以会按照 bean 配置的顺序保存每一个注册的 Bean 的名
    字
    this.beanDefinitionNames.add(beanName);
    //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    this.manualSingletonNames.remove(beanName);
    }
    // 这个不重要,在预初始化的时候会用到,不必管它

4.3 容器13大模板方法之三:prepareBeanFactory(beanFactory)

【准备bean工厂】

    //3、【准备bean工厂】为BeanFactory配置容器特性,例如类加载器、表达式解析器、注册默认环
    境、后置管理器
    prepareBeanFactory(beanFactory);
    /1、设置 BeanFactory 的类加载器
    //2、设置 BeanFactory 的表达式解析器
    //3、设置 BeanFactory 的属性编辑器
    //4、智能注册

tips
当前代码逻辑简单、且非核心

4.4 容器13大模板方法之四:postProcessBeanFactory(beanFactory)

【后置处理器Bean工厂】空方法

    // 4、【后置处理器Bean工厂】此处为空方法,子类的实现
    postProcessBeanFactory(beanFactory);

需要注意:
BeanFactoryPostProcessor和BeanPostProcessor,此处是前者
BeanFactoryPostProcessor 是容器级别的后处理器,对其他容器中的bean 没有影响

tips:子类实现skip当前方法

4.5 容器13大模板方法之五:invokeBeanFactoryPostProcessors()

【调用bean工厂后置处理器】

    //调用顺序一:bean定义注册后置处理器
    //调用顺序二:bean工厂后置处理器
    //重点
    //执行bean定义注册后置处理器!!!!!!!!!!!!
    //执行BeanF工厂后置处理器!!!!!!!!!!!!!!!!!!!!!!!!!!!
    public static void invokeBeanFactoryPostProcessors()

讲解重点(断点跟踪、类继承关系、架构图讲解)
关于invokeBeanFactoryPostProcessors为什么为true?

    if (beanFactory instanceof BeanDefinitionRegistry) {
    ...略
    }

202209112138443535.png

找到核心逻辑

    //164行
    // 执行bean定义注册后置处理器!!!!!!!!!!!!
    invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    //222行
    //执行BeanF工厂后置处理器!!!!!!!!!!!!!!!!!!!!!!!!!!!
    invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

找到我们项目中的自定义两个处理器
进行断点追踪执行过程

    com.spring.test.config.BeanDefinitionRegistryPostProcessorTest
    com.spring.test.config.BeanFactoryPostProcessorTest
    此次代码略..........

tips
invoke方法近200行,只看核心

4.6 容器13大模板方法之六:registerBeanPostProcessors(beanFactory)

【注册bean后置处理器】

    //6、【注册bean后置处理器】只是注册,但是不会反射调用
    //功能:找出所有实现BeanPostProcessor接口的类,分类、排序、注册
    registerBeanPostProcessors(beanFactory);

讲解重点(断点跟踪、类继承关系、架构图讲解)

    //调用顺序一:bean定义注册后置处理器
    //调用顺序二:bean工厂后置处理器
    // 核心:查看重要的3步;最终目的都是实现bean后置处理器的注册
    // 第一步: implement PriorityOrdered
    // 第二步: implement Ordered.
    // 第三步: Register all internal BeanPostProcessors.

4.7 容器13大模板方法之七:initMessageSource()

【初始化消息源】国际化问题i18n

    //7、【初始化消息源】国际化问题i18n,参照https://nacos.io/
    initMessageSource();
    DelegatingMessageSource dms = new DelegatingMessageSource();
    dms.setParentMessageSource(getInternalParentMessageSource());
    this.messageSource = dms;
    //将这个messageSource实例注册到Bean工厂中
    beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME,
    this.messageSource);

关于beanFactory.registerSingleton( org.springframework.beans.factory.support.DefaultListableBeanFactory#registerSingleton将新建的这个bean手动注册到bean工厂步骤如下

调用:
org.springframework.beans.factory.support.DefaultListableBeanFactory#manualSingletonNames 这个集合器set中然后:先去一级缓存去找,没有,直接放到一级缓存。移除二级三级缓存

最后:设置bean公厂、放到集合

202209112138456086.png

4.8 容器13大模板方法之八:initApplicationEventMulticaster()

【初始化应用程序事件多路广播】

    //8、【初始化应用程序事件多路广播】初始化自定义的事件监听多路广播器,(观察
    者)S
    initApplicationEventMulticaster();

tips:
需要理解观察者设计模式
重点:演示多播和容器发布

    /**
    * 如果没有,则默认采用SimpleApplicationEventMulticaster行事件的广播
    */
    this.applicationEventMulticaster = new
    SimpleApplicationEventMulticaster(beanFactory);
    //将多播注册到Bean工厂
    beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME,
    this.applicationEventMulticaster);

关于beanFactory.registerSingleton( org.springframework.beans.factory.support.DefaultListableBeanFactory#registerSingleton 将新建的这个bean手动注册到bean工厂
步骤如下
调用:
org.springframework.beans.factory.support.DefaultListableBeanFactory#manualSingletonNames 这个集合器set中
然后:先去一级缓存去找,没有,直接放到一级缓存。移除二级三级缓存
最后:设置bean公厂、放到集合

4.9 容器13大模板方法之九:onRefresh()

【刷新】 子实现:默认情况下不执行任何操作

    // 9、【刷新】具体的子类可以在这里初始化一些特殊的 Bean(在初始化singleton beans 之前)
    onRefresh();

4.10 容器13大模板方法之十:registerListeners()

【注册所有监听器】

    //10、【注册所有监听器】,监听器需要实现 ApplicationListener 接口。
    registerListeners();

讲解重点(断点跟踪、类继承关系、架构图讲解)

    //获取所有实现了ApplicationListener,然后进行注册
    //查找顺序
    //1、集合applicationListeners查找
    //2、bean工厂找到实现ApplicationListener接口的bean
    //3、this.earlyApplicationEvents;准备刷新(启动第一步设置)

4.11 容器13大模板方法十一:finishBeanFactoryInitialization(beanFactory)

核心:【完成bean工厂初始化操作】

    //11、 【完成bean工厂初始化操作】负责初始化所有的 singleton beans,反射生
    成对象/填充
    //此处开始调用Bean的前置处理器和后置处理器
    finishBeanFactoryInitialization(beanFactory);

讲解重点(断点跟踪、类继承关系、架构图讲解)

    //1、设置辅助器:例如:解析器、转换器、类装载器
    //2、实例化(反射)
    //3、填充
    //4、调用前置、后置处理器
    //1、先从一级缓存拿(or 正在创建中),如果正在创建有,最后return null,说明此处为实例化
    //2、在从二级缓存拿
    //3、在从三级缓存拿
    //以上三步为解决循环依赖
    //4、getBean调用的时候,直接从一级缓存取出
    @Nullable
    protected Object getSingleton(String beanName, boolean allowEarlyReference)
    {
    //先从一级缓存中拿,此处为空
    Object singletonObject = this.singletonObjects.get(beanName);
    // 下面isSingletonCurrentlyInCreation的如果有值,即为true,说明当前线程是实例化
    中...
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName))
    {
    synchronized (this.singletonObjects) {
    //在从二级缓存拿
    singletonObject = this.earlySingletonObjects.get(beanName);
    if (singletonObject == null && allowEarlyReference) {
    //在从三级缓存拿
    ObjectFactory<?> singletonFactory =
    this.singletonFactories.get(beanName);
    if (singletonFactory != null) {
    singletonObject = singletonFactory.getObject();
    this.earlySingletonObjects.put(beanName,
    singletonObject);
    this.singletonFactories.remove(beanName);
        }
       }
      }
     }
    return singletonObject;
    }

上面的代码总结:
先从一级缓存拿(此处如果为空,正在创建,直接return)为空,在从二级缓存拿还为空;在从三级缓存拿将三级缓存内容赋值给二级缓存
重点关注4个方法(重要)
调用时机:实例化(反射)对象/填充/回调后置(循环依赖&三级缓存)
调用入口:
xx.getBean()
容器初始化

    getBean
    doGetBean
    createBean
    doCreateBean

实例化核心

    org.springframework.beans.BeanUtils#instantiateClass(java.lang.reflect.Construct
    or<T>, java.lang.Object...)

注入核心

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#pop
    ulateBean

调用bean的前置、后置方法(这个时候bean已经实例化、注入完毕了)\

    //注意:
    //1、先调用bean的前置处理器
    //中间过程:调用bean的init方法或者实现了 InitializingBean 接口,调用
    afterPropertiesSet() 方法
    //2、后调用bean的后置处理器

最后一次机会的回调(实例化后注入前)

    org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#pop
    ulateBean
    ================================================================================
    ===
     boolean continueWithPropertyPopulation = true;
    //如果存在这实现这个接口的bean
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
    for (BeanPostProcessor bp : getBeanPostProcessors()) {
    if (bp instanceof InstantiationAwareBeanPostProcessor) {
    InstantiationAwareBeanPostProcessor ibp =
    (InstantiationAwareBeanPostProcessor) bp;
    // postProcessAfterInstantiation如果返回 false,代表不需要进行后
    续的属性设值
    if
    (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
    continueWithPropertyPopulation = false;
    break;
       }
      }
     }
    }

4.12 容器13大模板方法十二:finishRefresh()

【完成刷新】

    protected void finishRefresh() {
    // 1、清除上下文级资源缓存
    clearResourceCaches();
    // 2、LifecycleProcessor接口初始化
    // ps:当ApplicationContext启动或停止时,它会通过LifecycleProcessor来与所有声明
    的bean的周期做状态更新
    // 而在LifecycleProcessor的使用前首先需要初始化
    initLifecycleProcessor();
    // 3、启动所有实现了LifecycleProcessor接口的bean
    //DefaultLifecycleProcessor,默认实现
    getLifecycleProcessor().onRefresh();
    // 4、发布上下文刷新完毕事件到相应的监听器
    //ps:当完成容器初始化的时候,
    // 要通过Spring中的事件发布机制来发出ContextRefreshedEvent事件,以保证对应的监听
    器可以做进一步的逻辑处理
    publishEvent(new ContextRefreshedEvent(this));
    // 5、把当前容器注册到到MBeanServer,用于jmx使用
    LiveBeansView.registerApplicationContext(this);
    }

tips:
不重要

4.13 容器13大模板方法十三:resetCommonCaches()

【重设公共缓存】

    //15、重设公共缓存
    resetCommonCaches();
    //清除内核缓存;因为我们的对象已经实例化并且注入完毕了
    //中间过程数据(缓存)就不在需要了
    protected void resetCommonCaches() {
        //清除之前声明过的方法和列的缓存
    ReflectionUtils.clearCache();
    //清除解析类型的缓存、序列化缓存
    ResolvableType.clearCache();
    //清除所有的类加载器
    CachedIntrospectionResults.clearClassLoader(getClassLoader());
    }