show: stepversion: 1.0
enable_checker: true

浅谈SpringFramework IoC实现原理

提示:在前面的学习中,我们知道了Spring IoC容器的基本概念和基本应用
知道了Spring IoC容器的基本理论知识后,就可以尝试学习一下Spring源码,不过Spring源码比较复杂,所以本文不打算长篇大论,通过一些例子,一点点学习
提示:以下是本篇文章正文内容,下面案例可供参考

Spring IoC容器体系

Spring容器体系结构简述

上一章的学习中,我们已经比较详细地介绍了Spring IoC容器和简单应用,本文接着学习,可以参考Spring官网对IoC容器做了比较详细介绍,其中就指出了IoC容器在Spring框架中的实现核心是通过ApplicationContext,也可以说ApplicationContext是Spring IoC容器的表现:
在这里插入图片描述

  • 主要工程:org.springframework.beans、org.springframework.context
  • BeanFactory是顶级接口,ApplicationContext是高级接口,可以说是IoC的体现

    BeanFactory和Application的关系

    Alt+7查看BeanFactory的所有方法如图,从名称来看BeanFactory可以看出Beandefinition生成的工厂类
    在这里插入图片描述
    然后BeanFactory和Application的关系是怎么样的?可以用uml类图表示:从图可以看出BeanFactory是顶级接口类,而Application不仅实现了BeanFactory,而且还实现了MessageSource、EnvironmentCapable等等接口
    在这里插入图片描述
    总而言之,BeanFactory是顶级接口,ApplicationContext是高级接口,可以说是spring容器的表现

    ApplicationContext uml类图

    ApplicationContext主要有如下的实现类,当然5.0.x版本不止这几个,不过主要使用的还是这3个:

  • ClassPathXmlApplicationContext:从类根路径加载元数据

  • FileSystemXmlApplicationContext:从磁盘路径加载元数据
  • AnnotationConfigApplicationContext:通过注解配置类加载元数据

在idea中看一下实现的类图,从图,我们可以清晰地看出类具体的关系:
在这里插入图片描述
从图:我们挑出重点的类,AbstractApplicationContext,GenericApplicationContext,AbstractRefreshableConfigApplicationContext
在这里插入图片描述

Bean初始化主流程

ok,本文通过例子调试的方法,看看Bean是怎么通过IoC容器实例的

开发软件和实验环境准备

  • SpringFramework版本
  • Springframework5.0.x
  • 开发环境
  • JAR管理:gradle 4.9/ Maven3.+
  • 开发IDE:IntelliJ IDEA 2018.2.5
  • JDK:jdk1.8.0_31
  • Git Server:Git fro window 2.8.3
  • Git Client:SmartGit18.1.5(可选)

maven项目,需要加上pom配置:

  1. <properties>
  2. <springframework.version>5.0.9.RELEASE</springframework.version>
  3. </properties>
  4. <dependencies>
  5. <dependency>
  6. <groupId>org.springframework</groupId>
  7. <artifactId>spring-context</artifactId>
  8. <version>${springframework.version}</version>
  9. </dependency>
  10. </dependencies>

如果是gradle环境,可以直接在Spring框架project里新增一个module,具体可以参考教程:加上对应的配置
在这里插入图片描述

BeanDefinition初始化过程

新建一个测试的Bean类:

  1. package com.example.bean;
  2. import org.springframework.beans.factory.InitializingBean;
  3. public class SpringBean implements InitializingBean {
  4. public SpringBean(){
  5. System.out.println("SpringBean构造函数");
  6. }
  7. @Override
  8. public void afterPropertiesSet() throws Exception {
  9. System.out.println("SpringBean afterPropertiesSet");
  10. }
  11. }

配置类:注册Bean

  1. import com.example.bean.SpringBean;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. @Configuration
  5. public class AppConfiguration {
  6. @Bean
  7. public SpringBean springBean() {
  8. return new SpringBean();
  9. }
  10. }

测试类:本文先通过AnnotationConfigApplicationContext 进行学习

  1. import com.example.bean.SpringBean;
  2. import com.example.config.AppConfiguration;
  3. import org.springframework.context.annotation.AnnotationConfigApplicationContext;
  4. public class TestApplication {
  5. public static void main(String[] args) {
  6. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
  7. context.register(AppConfiguration.class);
  8. context.refresh();
  9. SpringBean bean = context.getBean(SpringBean.class);
  10. System.out.println(bean);
  11. }
  12. }

默认情况,也就是非懒加载的情况,经过调试,finishBeanFactoryInitialization(beanFactory);方法被调用后,调用了bean的构造函数,说明bean被实例了
在这里插入图片描述
通过@Lazy注解将bean设置为懒加载,在前面的学习,可以知道,所谓的懒加载就是在调用第一次调用bean时候才实例,不是在IoC容器启动就实例bean

  1. @Bean
  2. @Lazy
  3. public SpringBean springBean() {
  4. return new SpringBean();
  5. }

通过调试,懒加载的bean,在IoC容器启动之后,是不会被实例的,在代码SpringBean bean = context.getBean(SpringBean.class);调用时候,才会被实例
在这里插入图片描述

IoC容器初始化主过程

通过调试,我们找到AbstractApplicationContext的核心方法refresh,这个方法可以说是IoC容器启动的一条主线方法,找到这个方法,我们就可以对IoC启动的过程有一个比较清晰的路线
{@link org.springframework.context.support.AbstractApplicationContext#refresh}

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. // 注意:加了同步锁,保证容器的调用不冲突
  4. synchronized (this.startupShutdownMonitor) {
  5. // Prepare this context for refreshing.
  6. // 第一步:刷新Spring IoC容器前的预处理
  7. // 记录容器的启动时间,标记启动状态,处理配置文件占位符等等
  8. prepareRefresh();
  9. // Tell the subclass to refresh the internal bean factory.
  10. // 第二步:获取BeanFactory,默认实现是DefaultListableBeanFactory
  11. // 这一步比较重要,执行完成之后,xml配置会被解析成一个个BeanDefinition并注册到BeanFactory
  12. // 但是BeanDefinition还没实例完成,只是配置信息被提取处理
  13. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  14. // Prepare the bean factory for use in this context.
  15. // 第三步:BeanFactory的准备工作
  16. // 对BeanFactory进行一些配置,设置BeanFactory的类加载器等等
  17. prepareBeanFactory(beanFactory);
  18. try {
  19. // Allows post-processing of the bean factory in context subclasses.
  20. // 第四步:BeanFactory准备工作完成之后的后置处理
  21. // 添加一些BeanFactoryPostProcessor 实现类,典型模板方法(设计模式:模板模式),给子类实现
  22. postProcessBeanFactory(beanFactory);
  23. // Invoke factory processors registered as beans in the context.
  24. // 第五步:实例并调用(invoke)BeanFactoryPostProcessors接口的postProcessBeanFactory方法(BeanFactory后置处理器)
  25. invokeBeanFactoryPostProcessors(beanFactory);
  26. // Register bean processors that intercept bean creation.
  27. // 第六步:注册BeanPostProcessors实现类(Bean后置处理器)
  28. // BeanPostProcessors接口两个方法:postProcessBeforeInitialization 和 postProcessAfterInitialization
  29. // postProcessBeforeInitialization 和 postProcessAfterInitialization分别在Bean创建的前后执行
  30. registerBeanPostProcessors(beanFactory);
  31. // Initialize message source for this context.
  32. // 第七步:初始化MessageSource组件,用于实现国际化i18n功能,消息处理,消息绑定
  33. initMessageSource();
  34. // Initialize event multicaster for this context.
  35. // 第八步:初始化事件派发器
  36. initApplicationEventMulticaster();
  37. // Initialize other special beans in specific context subclasses.
  38. // 第九步:典型的模板方法(设计模式:模板模式),具体实现给子类实现,在IoC容器刷新时候添加自己的逻辑代码
  39. onRefresh();
  40. // Check for listener beans and register them.
  41. // 第十步:注册监听器,ApplicationListener接口的监听器
  42. registerListeners();
  43. // Instantiate all remaining (non-lazy-init) singletons.
  44. // 第十一步:非懒加载(lazy-init=false,默认)的单例bean初始化实例完成
  45. finishBeanFactoryInitialization(beanFactory);
  46. // Last step: publish corresponding event.
  47. // 第十二步:完成ApplicationContext的刷新,调用LifecycleProcessor的onRefresh方法
  48. finishRefresh();
  49. }
  50. catch (BeansException ex) {
  51. if (logger.isWarnEnabled()) {
  52. logger.warn("Exception encountered during context initialization - " +
  53. "cancelling refresh attempt: " + ex);
  54. }
  55. // Destroy already created singletons to avoid dangling resources.
  56. // 回收bean资源
  57. destroyBeans();
  58. // Reset 'active' flag.
  59. cancelRefresh(ex);
  60. // Propagate exception to caller.
  61. // 异常往上抛,具体实现类才能捕获到异常信息
  62. throw ex;
  63. }
  64. finally {
  65. // Reset common introspection caches in Spring's core, since we
  66. // might not ever need metadata for singleton beans anymore...
  67. // 刷新缓存
  68. resetCommonCaches();
  69. }
  70. }
  71. }

画思维导图表示核心过程:
在这里插入图片描述

浅谈prepareRefresh预加载过程

本文先简要跟下代码:

  1. protected void prepareRefresh() {
  2. // Switch to active.
  3. // 记录启动时间,active属性设置为true,closed属性设置为false
  4. this.startupDate = System.currentTimeMillis();
  5. this.closed.set(false);
  6. this.active.set(true);
  7. if (logger.isInfoEnabled()) {
  8. logger.info("Refreshing " + this);
  9. }
  10. // Initialize any placeholder property sources in the context environment.
  11. // 处理配置文件中的占位符
  12. initPropertySources();
  13. // Validate that all properties marked as required are resolvable:
  14. // see ConfigurablePropertyResolver#setRequiredProperties
  15. // 校验配置文件
  16. getEnvironment().validateRequiredProperties();
  17. // Store pre-refresh ApplicationListeners...
  18. if (this.earlyApplicationListeners == null) {
  19. this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
  20. }
  21. else {
  22. // Reset local application listeners to pre-refresh state.
  23. this.applicationListeners.clear();
  24. this.applicationListeners.addAll(this.earlyApplicationListeners);
  25. }
  26. // Allow for the collection of early ApplicationEvents,
  27. // to be published once the multicaster is available...
  28. this.earlyApplicationEvents = new LinkedHashSet<>();
  29. }

浅谈BeanFactory构建过程

{@link org.springframework.context.support.AbstractApplicationContext#refresh}obtainFreshBeanFactory方法:

  1. /**
  2. * Tell the subclass to refresh the internal bean factory.
  3. * @return the fresh BeanFactory instance
  4. * @see #refreshBeanFactory()
  5. * @see #getBeanFactory()
  6. */
  7. protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  8. // 创建BeanFactory
  9. refreshBeanFactory();
  10. // 返回refreshBeanFactory方法创建好的BeanFactory
  11. ConfigurableListableBeanFactory beanFactory = getBeanFactory();
  12. if (logger.isDebugEnabled()) {
  13. logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
  14. }
  15. return beanFactory;
  16. }

通过调试,默认的BeanFactoryDefaultListableBeanFactory,为什么是DefaultListableBeanFactory?可以找一下AnnotationConfigApplicationContext的uml类图,从图可以看出AnnotationConfigApplicationContext继承于GenericApplicationContext
在这里插入图片描述
Ctrl+Alt+B找到{@link org.springframework.context.support.GenericApplicationContext#getBeanFactory}

  1. private final DefaultListableBeanFactory beanFactory;
  2. /**
  3. * Return the single internal BeanFactory held by this context
  4. * (as ConfigurableListableBeanFactory).
  5. */
  6. @Override
  7. public final ConfigurableListableBeanFactory getBeanFactory() {
  8. return this.beanFactory;
  9. }

所以,默认的BeanFactory就是DefaultListableBeanFactory
接着往上继续跟refreshBeanFactory方法,Ctrl+Alt+B找到org.springframework.context.support.GenericApplicationContext#refreshBeanFactory,根据注释,找到registerBeanDefinition
在这里插入图片描述
{@link org.springframework.context.support.GenericApplicationContext#registerBeanDefinition}

  1. @Override
  2. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  3. throws BeanDefinitionStoreException {
  4. // 将BeanDefinition注册到BeanFactory
  5. this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
  6. }

{@link org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition},这里的逻辑比较复杂,需要跟一下代码:

  1. @Override
  2. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
  3. throws BeanDefinitionStoreException {
  4. Assert.hasText(beanName, "Bean name must not be empty");
  5. Assert.notNull(beanDefinition, "BeanDefinition must not be null");
  6. // 校验BeanDefinition必须是AbstractBeanDefinition的子类
  7. if (beanDefinition instanceof AbstractBeanDefinition) {
  8. try {
  9. ((AbstractBeanDefinition) beanDefinition).validate();
  10. }
  11. catch (BeanDefinitionValidationException ex) {
  12. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  13. "Validation of bean definition failed", ex);
  14. }
  15. }
  16. // 单例Bean信息保存在beanDefinitionMap里
  17. BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
  18. if (existingDefinition != null) {
  19. // 是否允许BeanDefinition覆盖
  20. // 意思是:举个例子两个bean的id和name是相同的,在同个配置文件里这种情况是会抛异常的,在不同配置文件会进行覆盖
  21. if (!isAllowBeanDefinitionOverriding()) {
  22. // 不允许覆盖,抛出异常
  23. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
  24. "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
  25. "': There is already [" + existingDefinition + "] bound.");
  26. }
  27. else if (existingDefinition.getRole() < beanDefinition.getRole()) {
  28. // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
  29. // 用框架定义的bean覆盖用户定义的bean,日志打印一些警告日志
  30. if (logger.isWarnEnabled()) {
  31. logger.warn("Overriding user-defined bean definition for bean '" + beanName +
  32. "' with a framework-generated bean definition: replacing [" +
  33. existingDefinition + "] with [" + beanDefinition + "]");
  34. }
  35. }
  36. else if (!beanDefinition.equals(existingDefinition)) {
  37. // 用新的bean覆盖旧的bean,同样会打印日志提示
  38. if (logger.isInfoEnabled()) {
  39. logger.info("Overriding bean definition for bean '" + beanName +
  40. "' with a different definition: replacing [" + existingDefinition +
  41. "] with [" + beanDefinition + "]");
  42. }
  43. }
  44. else {
  45. if (logger.isDebugEnabled()) {
  46. logger.debug("Overriding bean definition for bean '" + beanName +
  47. "' with an equivalent definition: replacing [" + existingDefinition +
  48. "] with [" + beanDefinition + "]");
  49. }
  50. }
  51. // 将beanDefinition保存到beanDefinitionMap
  52. this.beanDefinitionMap.put(beanName, beanDefinition);
  53. }
  54. else {
  55. // 判断是否已经有其他的 Bean 开始初始化了,要加上同步锁,避免冲突
  56. if (hasBeanCreationStarted()) {
  57. // Cannot modify startup-time collection elements anymore (for stable iteration)
  58. // 加上同步锁,避免多个bean加载到beanDefinitionMap冲突(用于稳定迭代)
  59. synchronized (this.beanDefinitionMap) {
  60. this.beanDefinitionMap.put(beanName, beanDefinition);
  61. List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
  62. updatedDefinitions.addAll(this.beanDefinitionNames);
  63. updatedDefinitions.add(beanName);
  64. this.beanDefinitionNames = updatedDefinitions;
  65. if (this.manualSingletonNames.contains(beanName)) {
  66. Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
  67. updatedSingletons.remove(beanName);
  68. this.manualSingletonNames = updatedSingletons;
  69. }
  70. }
  71. }
  72. else {
  73. // Still in startup registration phase
  74. // 其它情况: 这种是理想的情况
  75. // beanDefinitionMap保存beanDefinition,注册beanDefinitionNames,manualSingletonNames
  76. this.beanDefinitionMap.put(beanName, beanDefinition);
  77. this.beanDefinitionNames.add(beanName);
  78. this.manualSingletonNames.remove(beanName);
  79. }
  80. this.frozenBeanDefinitionNames = null;
  81. }
  82. if (existingDefinition != null || containsSingleton(beanName)) {
  83. resetBeanDefinition(beanName);
  84. }
  85. else if (isConfigurationFrozen()) {
  86. clearByTypeCache();
  87. }
  88. }

BeanFactoryPostProcessor调用过程

为了验证BeanFactoryPostProcessor的调用过程,我们想知道BeanFactoryPostProcessor什么时候被实例,时候时候才被调用,我们可以通过写个例子进行验证:

  1. package com.example.config;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
  4. import org.springframework.beans.factory.config.BeanPostProcessor;
  5. import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
  6. import org.springframework.stereotype.Component;
  7. /**
  8. *
  9. <pre>
  10. * CustomBeanFactoryPostProcessor
  11. * </pre>
  12. *
  13. *
  14. <pre>
  15. * @author mazq
  16. * 修改记录
  17. * 修改后版本: 修改人: 修改日期: 2020/11/05 15:21 修改内容:
  18. * </pre>
  19. */
  20. //@Component
  21. public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor{
  22. public CustomBeanFactoryPostProcessor(){
  23. System.out.println("CustomBeanFactoryPostProcessor构造函数被调用");
  24. }
  25. /**
  26. * Modify the application context's internal bean factory after its standard
  27. * initialization. All bean definitions will have been loaded, but no beans
  28. * will have been instantiated yet. This allows for overriding or adding
  29. * properties even to eager-initializing beans.
  30. *
  31. * @param beanFactory the bean factory used by the application context
  32. * @throws BeansException in case of errors
  33. */
  34. @Override
  35. public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
  36. System.out.println("postProcessBeanFactory方法被调用");
  37. }
  38. }

AppConfiguration 配置类:

  1. package com.example.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. /**
  5. *
  6. <pre>
  7. * AppConfiguration
  8. * </pre>
  9. *
  10. *
  11. <pre>
  12. * @author mazq
  13. * 修改记录
  14. * 修改后版本: 修改人: 修改日期: 2020/11/05 10:26 修改内容:
  15. * </pre>
  16. */
  17. @Configuration
  18. public class AppConfiguration {
  19. @Bean
  20. public CustomBeanFactoryPostProcessor customBeanFactoryPostProcessor(){
  21. return new CustomBeanFactoryPostProcessor();
  22. }
  23. }
  1. public static void main(String[] args) {
  2. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
  3. context.register(AppConfiguration.class);
  4. context.refresh();
  5. SpringBean bean = context.getBean(SpringBean.class);
  6. System.out.println(bean);
  7. }

然后在构造函数和postProcessBeanFactory方法处打断点,debug运行,通过debug,在invokeBeanFactoryPostProcessors时候,构造函数和postProcessBeanFactory都被调用了,说明了BeanFactoryPostProcessor的初始化和调用都是在invokeBeanFactoryPostProcessors执行时候触发
在这里插入图片描述

BeanPostProcessor 调用过程

接着,验证BeanPostProcessor 什么时候被实例,时候时候才被调用,我们也可以通过例子调试验证:

  1. package com.example.config;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.beans.factory.config.BeanPostProcessor;
  4. /**
  5. *
  6. <pre>
  7. * CustomBeanPostProcessor
  8. * </pre>
  9. *
  10. *
  11. <pre>
  12. * @author mazq
  13. * 修改记录
  14. * 修改后版本: 修改人: 修改日期: 2020/11/05 10:55 修改内容:
  15. * </pre>
  16. */
  17. public class CustomBeanPostProcessor implements BeanPostProcessor {
  18. public CustomBeanPostProcessor() {
  19. System.out.println("BeanPostProcessor构造函数被调用");
  20. }
  21. @Override
  22. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
  23. if ("springBean".equals(beanName)) {
  24. System.out.println("postProcessBeforeInitialization方法被调用,对应的beanName是springBean");
  25. }
  26. return bean;
  27. }
  28. @Override
  29. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
  30. if ("springBean".equals(beanName)) {
  31. System.out.println("postProcessAfterInitialization,对应的beanName是springBean");
  32. }
  33. return bean;
  34. }
  35. }

配置类,将bean加载到ioc容器:

  1. package com.example.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. /**
  5. *
  6. <pre>
  7. * AppConfiguration
  8. * </pre>
  9. *
  10. *
  11. <pre>
  12. * @author mazq
  13. * 修改记录
  14. * 修改后版本: 修改人: 修改日期: 2020/11/05 10:26 修改内容:
  15. * </pre>
  16. */
  17. @Configuration
  18. public class AppConfiguration {
  19. @Bean
  20. public CustomBeanPostProcessor customBeanPostProcessor(){
  21. return new CustomBeanPostProcessor();
  22. }
  23. }

在这里插入图片描述
在这里插入图片描述
经过调试,BeanPostProcessor初始化实例是在#refresh.registerBeanPostProcessors时候触发的,调用是在#refresh.finishBeanFactoryInitialization时候被触发的
ok,基于前面的实验,可以归纳比对一下BeanFactoryPostProcessorBeanPostProcessor,这两个比较重要的接口:

| 接口关键点 | 方法 | | —- | —- |

| BeanFactoryPostProcessor初始化 | #refresh.invokeBeanFactoryPostProcessors(beanFactory) |

| BeanFactoryPostProcessor调用 | #refresh.invokeBeanFactoryPostProcessors(beanFactory) |

| BeanPostProcessor 初始化 | #refresh.registerBeanPostProcessors(beanFactory) |

| BeanPostProcessor 调用 | #refresh.finishBeanFactoryInitialization(beanFactory) |

CustomBeanFactoryPostProcessor构造函数被调用
postProcessBeanFactory方法被调用
BeanPostProcessor构造函数被调用
SpringBean构造函数
postProcessBeforeInitialization方法被调用,对应的beanName是springBean
SpringBean afterPropertiesSet
postProcessAfterInitialization,对应的beanName是springBean
com.example.bean.SpringBean30ee2816