• Spring IoC容器初始化主体流程


    1、Spring IoC的容器体系

    IoC容器是Spring的核心模块,是抽象了对象管理、依赖关系管理的框架解决方案。Spring 提供了很多的容器,其中 BeanFactory 是顶层容器(根容器),不能被实例化,它定义了所有 IoC 容器 必须遵从的⼀套原则,具体的容器实现可以增加额外的功能,比如我们常用到的ApplicationContext,其下更具体的实现如 ClassPathXmlApplicationContext 包含了解析 xml 等⼀系列的内容,AnnotationConfigApplicationContext 则是包含了注解解析等⼀系列的内容。Spring IoC 容器继承体系⾮常聪明,需要使⽤哪个层次⽤哪个层次即可,不必使⽤功能⼤而全的。

    BeanFactory 顶级接⼝方法栈如下

     

    BeanFactory 容器继承体系

    通过其接⼝设计,我们可以看到我们⼀贯使⽤的 ApplicationContext 除了继承BeanFactory的⼦接⼝,还继承了ResourceLoader、MessageSource等接⼝,因此其提供的功能也就更丰富了。
    下⾯我们以 ClasspathXmlApplicationContext 为例,深⼊源码说明 IoC 容器的初始化流程。

     

    2、Bean生命周期关键时机点

    思路:创建⼀个类 LagouBean ,让其实现⼏个特殊的接⼝,并分别在接⼝实现的构造器、接⼝⽅法中断点,观察线程调⽤栈,分析出 Bean 对象创建和管理关键点的触发时机。

    LagouBean类

    1. import org.springframework.beans.BeansException;
    2. import org.springframework.beans.factory.DisposableBean;
    3. import org.springframework.beans.factory.InitializingBean;
    4. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    5. import org.springframework.beans.factory.config.BeanPostProcessor;
    6. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    7. import org.springframework.stereotype.Component;
    8. public class LagouBean implements InitializingBean {
    9. /**
    10. * 构造函数
    11. */
    12. public LagouBean() {
    13. System.out.println("LagouBean 构造器...");
    14. }
    15. /**
    16. * InitializingBean 接⼝实现
    17. */
    18. public void afterPropertiesSet() throws Exception {
    19. System.out.println("LagouBean afterPropertiesSet...");
    20. }
    21. }

    BeanPostProcessor 接⼝实现类

    1. import org.springframework.beans.BeansException;
    2. import org.springframework.beans.factory.config.BeanPostProcessor;
    3. import org.springframework.stereotype.Component;
    4. public class MyBeanPostProcessor implements BeanPostProcessor {
    5. public MyBeanPostProcessor() {
    6. System.out.println("BeanPostProcessor 实现类构造函数...");
    7. }
    8. @Override
    9. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    10. if ("lagouBean".equals(beanName)) {
    11. System.out.println("BeanPostProcessor 实现类 postProcessBeforeInitialization ⽅法被调⽤中......");
    12. }
    13. return bean;
    14. }
    15. @Override
    16. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    17. if ("lagouBean".equals(beanName)) {
    18. System.out.println("BeanPostProcessor 实现类 postProcessAfterInitialization ⽅法被调⽤中......");
    19. }
    20. return bean;
    21. }
    22. }

    BeanFactoryPostProcessor 接⼝实现类

    1. import org.springframework.beans.BeansException;
    2. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
    3. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
    4. import org.springframework.stereotype.Component;
    5. public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    6. public MyBeanFactoryPostProcessor() {
    7. System.out.println("BeanFactoryPostProcessor的实现类构造函数...");
    8. }
    9. @Override
    10. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    11. System.out.println("BeanFactoryPostProcessor的实现⽅法调⽤中......");
    12. }
    13. }

    applicationContext.xml

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="
    5. http://www.springframework.org/schema/beans
    6. https://www.springframework.org/schema/beans/spring-beans.xsd
    7. ">
    8. <bean id="lagouBean" class="com.lagou.LagouBean"/>
    9. <bean id="myBeanFactoryPostProcessor" class="com.lagou.MyBeanFactoryPostProcessor"/>
    10. <bean id="myBeanPostProcessor" class="com.lagou.MyBeanPostProcessor"/>
    11. </beans>

    IoC 容器源码分析⽤例

    1. /**
    2. * Ioc 容器源码分析基础案例
    3. */
    4. @Test
    5. public void testIoC(){
    6. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    7. LagouBean lagouBean=applicationContext.getBean(LagouBean.class);
    8. System.out.println(lagouBean);
    9. }

    2.1、分析 Bean 的创建是在容器初始化时还是在 getBean 时

    根据断点调试,我们发现,在未设置延迟加载的前提下,Bean 的创建是在容器初始化过程中完成的。

    2.2、分析构造函数调用情况 

     

    通过如上观察,我们发现构造函数的调⽤时机在AbstractApplicationContext类refresh⽅法的finishBeanFactoryInitialization(beanFactory)处; 

    2.3、分析 InitializingBean 之 afterPropertiesSet 初始化方法调用情况

    观察调⽤栈

     

    通过如上观察,我们发现 InitializingBean中afterPropertiesSet 方法的调用时机也是在AbstractApplicationContext类refresh方法的finishBeanFactoryInitialization(beanFactory); 

    2.4、分析BeanFactoryPostProcessor 初始化和调用情况 

    分别在构造函数、postProcessBeanFactory 方法处打断点,观察调用栈,发现
    BeanFactoryPostProcessor 初始化在AbstractApplicationContext类refresh方法的invokeBeanFactoryPostProcessors(beanFactory);

    postProcessBeanFactory 调用在AbstractApplicationContext类refresh方法的invokeBeanFactoryPostProcessors(beanFactory); 

    2.5、分析 BeanPostProcessor 初始化和调用情况

    分别在构造函数、postProcessBeanFactory 方法处打断点,观察调用栈,发现
    BeanPostProcessor 初始化在AbstractApplicationContext类refresh方法的
    registerBeanPostProcessors(beanFactory);

    postProcessBeforeInitialization 调用在AbstractApplicationContext类refresh方法的
    finishBeanFactoryInitialization(beanFactory);

    postProcessAfterInitialization 调用在AbstractApplicationContext类refresh方法的
    finishBeanFactoryInitialization(beanFactory); 

    2.6、总结

    根据上面的调试分析,我们发现 Bean对象创建的几个关键时机点代码层级的调用都在
    AbstractApplicationContext 类 的 refresh 方法中,可见这个方法对于Spring IoC 容器初始化来说相当关键,汇总如下: 

    关键点触发代码
    构造器refresh#finishBeanFactoryInitialization(beanFactory)(beanFactory)
    BeanFactoryPostProcessor 初始化refresh#invokeBeanFactoryPostProcessors(beanFactory)
    BeanFactoryPostProcessor 方法调用refresh#invokeBeanFactoryPostProcessors(beanFactory)
    BeanPostProcessor 初始化registerBeanPostProcessors(beanFactory)
    BeanPostProcessor 方法调用refresh#finishBeanFactoryInitialization(beanFactory)

    3、Spring IoC容器初始化主流程

    由上分析可知,Spring IoC 容器初始化的关键环节就在 AbstractApplicationContext#refresh() 方法中,我们查看 refresh 方法来俯瞰容器创建的主体流程,主体流程下的具体子流程我们后面再来讨论。 

    1. @Override
    2. public void refresh() throws BeansException, IllegalStateException {
    3. synchronized (this.startupShutdownMonitor) {
    4. // 第⼀步:刷新前的预处理
    5. prepareRefresh();
    6. /*
    7. 第⼆步:
    8. 获取BeanFactory;默认实现是DefaultListableBeanFactory
    9. 加载BeanDefition 并注册到 BeanDefitionRegistry
    10. */
    11. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    12. // 第三步:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)
    13. prepareBeanFactory(beanFactory);
    14. try {
    15. // 第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作
    16. postProcessBeanFactory(beanFactory);
    17. // 第五步:实例化并调⽤实现了BeanFactoryPostProcessor接⼝的Bean
    18. invokeBeanFactoryPostProcessors(beanFactory);
    19. // 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏
    20. registerBeanPostProcessors(beanFactory);
    21. // 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
    22. initMessageSource();
    23. // 第⼋步:初始化事件派发器
    24. initApplicationEventMulticaster();
    25. // 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
    26. onRefresh();
    27. // 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean
    28. registerListeners();
    29. /*
    30. 第⼗⼀步:
    31. 初始化所有剩下的⾮懒加载的单例bean
    32. 初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
    33. 填充属性
    34. 初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)
    35. 调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
    36. */
    37. finishBeanFactoryInitialization(beanFactory);
    38. /*
    39. 第⼗⼆步:
    40. 完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事
    41. 件 (ContextRefreshedEvent)
    42. */
    43. finishRefresh();
    44. }
    45. ......
    46. }
    47. }

  • 相关阅读:
    zabbix自定义监控、钉钉、邮箱报警 (五十六)
    自动驾驶技术中常用英文单词及缩略语整理
    武汉大学:浅议重保期间的邮件防护
    Nginx网站服务
    MySQL性能优化 - 别再只会说加索引了
    PHP:运算符优先级
    读取服务器文件,并进行移动-ChannelSftp
    《Unix 网络编程》05:TCP C/S 程序示例
    FoFa 查询工具(fofax)
    FS4064 SOP8 两节8.4V线性锂电池充电IC
  • 原文地址:https://blog.csdn.net/weixin_52851967/article/details/125519106