万隆的笔记 万隆的笔记
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
博文索引
笔试面试
  • 在线学站

    • 菜鸟教程 (opens new window)
    • 入门教程 (opens new window)
    • Coursera (opens new window)
  • 在线文档

    • w3school (opens new window)
    • Bootstrap (opens new window)
    • Vue (opens new window)
    • 阿里开发者藏经阁 (opens new window)
  • 在线工具

    • tool 工具集 (opens new window)
    • bejson 工具集 (opens new window)
    • 文档转换 (opens new window)
  • 更多在线资源
  • Changlog
  • Aboutme
GitHub (opens new window)
  • Spring

    • Spring简介
    • Spring核心思想
    • 手写实现IoC和AOP
    • Spring Web与Bean装配
    • Spring Transaction
    • Spring Validation
    • Spring IoC基础应用
    • Spring IoC高级特性
    • Spring IoC源码剖析
      • Spring IoC容器初始化主流程
      • BeanFactory创建流程
      • Bean创建流程
      • lazy-init 延迟加载机制原理
      • Spring IoC循环依赖问题
    • Spring AOP应用
    • Spring AOP声明式事务
    • Spring AOP源码剖析
  • SprinvMVC

  • SpringBoot

  • Spring
  • Spring
2023-02-04
目录

Spring IoC源码剖析

# Spring IoC源码深度剖析

阅读源码原则:

  • 定焦原则:抓主线
  • 宏观原则:站在上帝视⻆,关注源码结构和业务流程,淡化具体某⾏代码的编写细节

阅读技巧:

  • 打断点,观察调⽤栈
  • 查反调,Find Usages
  • 经验:Spring框架中doXXX,做具体处理的地⽅

Spring源码编译顺序:core->oxm->context->beans->aspects-aop,下文Spring源码基于5.3.x。

# Spring IoC容器初始化主流程

# Spring IoC的容器体系

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

ApplicationContext

Spring应用上下文,官方称之为 IoC容器。通常一些人错误地认为:容器就是Map而已,但准确来说,Map是IoC容器的一个成员,叫做单例池, singletonObjects。而容器是一组组件和过程的集合,包括BeanFactory、单例池、BeanPostProcessor等以及之间的协作流程。

BeanFactory 顶级接⼝⽅法定义如下:

bean_factory

BeanFactory 顶级接⼝集成体系如下:

app-class

beanfactory_class

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

# Bean⽣命周期关键时机点

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

InitializingBean接口&ApplicationContextAware接口实现类-SpringBean:

public class SpringBean implements InitializingBean, ApplicationContextAware {

	public SpringBean() {
		System.out.println("SpringBean 构造器...");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("SpringBean afterPropertiesSet...");
	}

	public void print() {
		System.out.println("print方法业务逻辑执行");
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		System.out.println("setApplicationContext...." + applicationContext);
	}

}

BeanPostProcessor接口实现类-MyBeanPostProcessor:

public class MyBeanPostProcessor implements BeanPostProcessor {

	public MyBeanPostProcessor() {
		System.out.println("MyBeanPostProcessor 实现类构造函数...");
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if("springBean".equals(beanName)) {
			System.out.println("MyBeanPostProcessor postProcessBeforeInitialization 方法被调用中......");
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if("springBean".equals(beanName)) {
			System.out.println("MyBeanPostProcessor postProcessAfterInitialization 方法被调用中......");
		}
		return bean;
	}

}

BeanFactoryPostProcessor接⼝实现类-MyBeanFactoryPostProcessor

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	public MyBeanFactoryPostProcessor() {
		System.out.println("BeanFactoryPostProcessor的实现类构造函数...");
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("BeanFactoryPostProcessor的实现方法调用中......");
	}

}

对应的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:aop="http://www.springframework.org/schema/aop"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="
	    http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
">

	<bean id="springBean" class="com.example.spring.learn.SpringBean"/>
	<bean id="myBeanPostProcessor" class="com.example.spring.learn.MyBeanPostProcessor"/>
	<bean id="myBeanFactoryPostProcessor" class="com.example.spring.learn.MyBeanFactoryPostProcessor"/>

</beans>

IoC 容器源码分析⽤例:

	@Test
	public void testIoC() {
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		SpringBean bean = applicationContext.getBean(SpringBean.class);
		System.out.println(bean);
	}

问题一:分析Bean的创建是在容器初始化时还是在getBean时?

spring_getBean

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

问题二:分析构造函数调⽤情况,观察调⽤栈。

spring_src_beaninit_1

spring_src_beaninit_2

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

问题三:分析 InitializingBean 之 afterPropertiesSet 初始化⽅法调⽤情况

afterProp1

afterProp2

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

下文打断点的方式类似,观察调用栈的方式,不重复截图赘述。

问题四:分析BeanFactoryPostProcessor 初始化和调⽤情况

beanFactory

分别在构造函数、postProcessBeanFactory ⽅法处打断点,观察调⽤栈,发现调用时机都在AbstractApplicationContext类refresh⽅法的invokeBeanFactoryPostProcessors(beanFactory);

问题五:分析 BeanPostProcessor 初始化和调⽤情况

postcessor1

postcessor1

分别在构造函数、postProcessBeanFactory ⽅法处打断点,观察调⽤栈,发现:

  • BeanPostProcessor 初始化在AbstractApplicationContext类refresh⽅法的registerBeanPostProcessors(beanFactory);
  • postProcessBeforeInitialization、postProcessBeforeInitialization 调⽤在AbstractApplicationContext类refresh⽅法的finishBeanFactoryInitialization(beanFactory);

总结:根据上⾯的调试分析,我们发现 Bean对象创建的⼏个关键时机点的调⽤都在AbstractApplicationContext 类 的 refresh ⽅法中,可⻅这个⽅法对于Spring IoC 容器初始化来说相当关键,汇总如下:

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

# [重点]Spring IoC容器初始化主流程

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

@Override
public void refresh() throws BeansException, IllegalStateException {
  // 对象锁加锁
  synchronized (this.startupShutdownMonitor) {
    StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

    /* Step1: Prepare this context for refreshing.
     * 刷新前的预处理,设置Spring容器启动时间、开启活跃状态、撤销关闭状态、验证环境信息里一些必须存在的属性等。
     */
    prepareRefresh();

    /* Step2: Tell the subclass to refresh the internal bean factory.
     * 获取BeanFactory,默认实现是DefaultListableBeanFactory
     * 加载BeanDefinition并注册到 BeanDefinitionRegistry
     */
    ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

    /* Step3: Prepare the bean factory for use in this context.
     * BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加载器等)
     */
    prepareBeanFactory(beanFactory);

    try {
      /* Step4: Allows post-processing of the bean factory in context subclasses.
       * BeanFactory准备工作完成后进行的后置处理工作
       */
      postProcessBeanFactory(beanFactory);

      StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
      /* Step5: Invoke factory processors registered as beans in the context.
       * 实例化实现了BeanFactoryPostProcessor接口的Bean,并调用接口方法
       */
      invokeBeanFactoryPostProcessors(beanFactory);

      /* Step6: Register bean processors that intercept bean creation.
       * 注册BeanPostProcessor(Bean的后置处理器),在创建Bean的前后等执行
       */
      registerBeanPostProcessors(beanFactory);
      beanPostProcess.end();

      /* Step7: Initialize message source for this context.
       * 初始化MessageSource组件, 国际化功能、消息绑定、消息解析
       */
      initMessageSource();

      /* Step8: Initialize event multicaster for this context.
       * 初始化事件派发器
       */
      initApplicationEventMulticaster();

      /* Step9: Initialize other special beans in specific context subclasses.
       * 子类重写这个方法,在容器刷新的时候可以自定义逻辑,如创建Tomcat,Jetty等WEB服务器
       */
      onRefresh();

      /* Step10: Check for listener beans and register them.
       * 注册应用的监听器,及时注册实现了ApplicationListener接口的监听器Bean
       */
      registerListeners();

      /* Step11: Instantiate all remaining (non-lazy-init) singletons.
       * 【重点】初始化所有剩下的非懒加载的单例Bean
       * 1. 初始化创建非懒加载方式的单例Bean实例(未设置属性)
       * 2. 填充属性
       * 3. 初始化方法调用,比如afterPropertiesSet方法、init-method方法
       * 4. 调用BeanPostProcessor后置处理器,对实例Bean进行后置处理
       * */
      finishBeanFactoryInitialization(beanFactory);

      /* Step12: ast step: publish corresponding event.
       * 完成context的刷新,主要调用LifecycleProcessor的onRefresh()方法,并发布事件(ContextRefreshEvent)
       * */
      finishRefresh();
    }

    catch (BeansException ex) {
      if (logger.isWarnEnabled()) {
        logger.warn("Exception encountered during context initialization - " +
            "cancelling refresh attempt: " + ex);
      }

      // Destroy already created singletons to avoid dangling resources.
      destroyBeans();

      // Reset 'active' flag.
      cancelRefresh(ex);

      // Propagate exception to caller.
      throw ex;
    }

    finally {
      // Reset common introspection caches in Spring's core, since we
      // might not ever need metadata for singleton beans anymore...
      resetCommonCaches();
      contextRefresh.end();
    }
  }
}

# BeanFactory创建流程

# 获取BeanFactory⼦流程

时序图如下:

beanFactoryPipleline

# BeanDefinition加载解析及注册⼦流程

# 关键步骤:

  • Resource定位:指对BeanDefinition的资源定位过程。通俗讲就是找到定义JavaBean信息的XML⽂件,并将其封装成Resource对象。
  • BeanDefinition载⼊:把⽤户定义好的JavaBean表示为IoC容器内部的数据结构,这个容器内部的数据结构就是BeanDefinition。
  • 注册BeanDefinition到IoC容器

# 过程分析

  1. Step 1:⼦流程⼊⼝在org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory⽅法中:

    @Override
    protected final void refreshBeanFactory() throws BeansException {
      // 判断是否有bean factory
      if (hasBeanFactory()) {
        // 销毁 beans
        destroyBeans();
        // 关闭 bean factory
        closeBeanFactory();
      }
      try {
        // 实例化 DefaultListableBeanFactory
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        // 设置序列化id
        beanFactory.setSerializationId(getId());
        // 自定义bean工厂的一些属性(是否覆盖、是否允许循环依赖)
        customizeBeanFactory(beanFactory);
        // !加载应用中的BeanDefinitions
        loadBeanDefinitions(beanFactory);
        // 赋值当前bean factory
        this.beanFactory = beanFactory;
      }
      catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
      }
    }
    
  2. Step 2:依次调⽤多个类的 loadBeanDefinitions ⽅法:AbstractXmlApplicationContext —> AbstractBeanDefinitionReader —> XmlBeanDefinitionReader,⼀直执⾏到 XmlBeanDefinitionReader 的 doLoadBeanDefinitions ⽅法:

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
        throws BeanDefinitionStoreException {
    
      try {
        // 读取xml信息,将xml中信息保存到Document对象
        Document doc = doLoadDocument(inputSource, resource);
        // 解析document对象,封装BeanDefinition对象并进行注册
        int count = registerBeanDefinitions(doc, resource);
        if (logger.isDebugEnabled()) {
          logger.debug("Loaded " + count + " bean definitions from " + resource);
        }
        return count;
      }
      catch (BeanDefinitionStoreException ex) {
        // ......
      }
      // 多个catch ....
    }
    
    
  3. Step 3:我们重点观察XmlBeanDefinitionReader 类的 registerBeanDefinitions ⽅法:

    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
      BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
      // 获取已有BeanDefinition数量
      int countBefore = getRegistry().getBeanDefinitionCount();
      // !注册BeanDefinition
      documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
      // 返回新注册的BeanDefinition数量
      return getRegistry().getBeanDefinitionCount() - countBefore;
    }
    

    此处我们关注两个地⽅:⼀个createRederContext⽅法,⼀个是 DefaultBeanDefifinitionDocumentReader类的registerBeanDefifinitions⽅法,先进⼊createRederContext ⽅法看看:

    public XmlReaderContext createReaderContext(Resource resource) {
      return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
          this.sourceExtractor, this, getNamespaceHandlerResolver());
    }
    
    public NamespaceHandlerResolver getNamespaceHandlerResolver() {
      if (this.namespaceHandlerResolver == null) {
        this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();
      }
      return this.namespaceHandlerResolver;
    }
    
    protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
      ResourceLoader resourceLoader = getResourceLoader();
      ClassLoader cl = (resourceLoader != null ? resourceLoader.getClassLoader() : getBeanClassLoader());
      return new DefaultNamespaceHandlerResolver(cl);
    }
    

    我们可以看到,此处 Spring ⾸先完成了 NamespaceHandlerResolver 的初始化。

    我们再进⼊ registerBeanDefinitions ⽅法中追踪,调⽤了org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#registerBeanDefinitions ⽅法:

    @Override
    public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
      this.readerContext = readerContext;
      doRegisterBeanDefinitions(doc.getDocumentElement());
    }
    

    进⼊ doRegisterBeanDefinitions ⽅法:

    @SuppressWarnings("deprecation")  // for Environment.acceptsProfiles(String...)
    protected void doRegisterBeanDefinitions(Element root) {
      // 委托模式,创建一个委托类
      BeanDefinitionParserDelegate parent = this.delegate;
      this.delegate = createDelegate(getReaderContext(), root, parent);
    
      if (this.delegate.isDefaultNamespace(root)) {
        String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
        if (StringUtils.hasText(profileSpec)) {
          String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
              profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
          // We cannot use Profiles.of(...) since profile expressions are not supported
          // in XML config. See SPR-12458 for details.
          if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
            if (logger.isDebugEnabled()) {
              logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
                  "] not matching: " + getReaderContext().getResource());
            }
            return;
          }
        }
      }
    
      // 钩子函数
      preProcessXml(root);
      // !解析BeanDefinition
      parseBeanDefinitions(root, this.delegate);
      // 钩子函数
      postProcessXml(root);
    
      this.delegate = parent;
    }
    

    进⼊ parseBeanDefinitions ⽅法:

    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
      if (delegate.isDefaultNamespace(root)) {
        NodeList nl = root.getChildNodes();
        for (int i = 0; i < nl.getLength(); i++) {
          Node node = nl.item(i);
          if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
              // !解析默认标签元素
              parseDefaultElement(ele, delegate);
            }
            else {
              // 解析自定义标签元素
              delegate.parseCustomElement(ele);
            }
          }
        }
      }
      else {
        delegate.parseCustomElement(root);
      }
    }
    

    进入parseDefaultElement方法:

    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
      // import元素处理
      if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
        importBeanDefinitionResource(ele);
      }
      // alias元素处理
      else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
        processAliasRegistration(ele);
      }
      // !bean元素处理
      else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
      }
      // 嵌套beans处理
      else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // recurse
        doRegisterBeanDefinitions(ele);
      }
    }
    

    进⼊ processBeanDefinition ⽅法:

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
      // 解析bean元素为BeanDefinition,但此时包装成了BeanDefinitionHolder对象
      BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
      if (bdHolder != null) {
        // 如果有自定义标签,则处理自定义标签
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
          // Register the final decorated instance.
          // 完成BeanDefinition的注册
          BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
          getReaderContext().error("Failed to register bean definition with name '" +
              bdHolder.getBeanName() + "'", ele, ex);
        }
        // Send registration event.
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
      }
    }
    

    进入 registerBeanDefinition 方法(org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition):

    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
        throws BeanDefinitionStoreException {
    
    	// ......
      BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
      if (existingDefinition != null) {
        // ......
        this.beanDefinitionMap.put(beanName, beanDefinition);
      }
      else {
        if (hasBeanCreationStarted()) {
          // Cannot modify startup-time collection elements anymore (for stable iteration)
          synchronized (this.beanDefinitionMap) {
            // ......
          }
        }
        else {
          // !Still in startup registration phase
          this.beanDefinitionMap.put(beanName, beanDefinition);
          this.beanDefinitionNames.add(beanName);
          removeManualSingletonName(beanName);
        }
        this.frozenBeanDefinitionNames = null;
      }
    
      if (existingDefinition != null || containsSingleton(beanName)) {
        resetBeanDefinition(beanName);
      }
      else if (isConfigurationFrozen()) {
        clearByTypeCache();
      }
    }
    

    ⾄此,注册流程结束,我们发现,所谓的注册就是把封装的 XML 中定义的 Bean信息封装为 BeanDefinition 对象之后放⼊⼀个Map中,BeanFactory 是以 Map 的结构组织这些BeanDefinition的。可以在DefaultListableBeanFactory中看到此Map的定义:

    /** Map of bean definition objects, keyed by bean name. */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    

# 时序图

BeanDefinitionPipleline.png

# Bean创建流程

之前的文章讲过 Spring Bean的生命周期,这里我们结合源码分析一下:

spring_bean_life

通过最开始的关键时机点分析,我们知道Bean创建⼦流程⼊⼝在AbstractApplicationContext#refresh()⽅法的finishBeanFactoryInitialization(beanFactory) 处:

/* Step11: Instantiate all remaining (non-lazy-init) singletons.
 * 【重点】初始化所有剩下的非懒加载的单例Bean
 * 1. 初始化创建非懒加载方式的单例Bean实例(未设置属性)
 * 2. 填充属性
 * 3. 初始化方法调用,比如afterPropertiesSet方法、init-method方法
 * 4. 调用BeanPostProcessor后置处理器,对实例Bean进行后置处理
 * */
finishBeanFactoryInitialization(beanFactory);

进⼊finishBeanFactoryInitialization:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
  // ......

  // Stop using the temporary ClassLoader for type matching.
  beanFactory.setTempClassLoader(null);

  // Allow for caching all bean definition metadata, not expecting further changes.
  beanFactory.freezeConfiguration();

  // Instantiate all remaining (non-lazy-init) singletons.
  // 实例化所有立即加载的bean
  beanFactory.preInstantiateSingletons();
}

继续进⼊DefaultListableBeanFactory类的preInstantiateSingletons⽅法,我们找到下⾯部分的代码,看到⼯⼚Bean或者普通Bean,最终都是通过getBean的⽅法获取实例:

@Override
public void preInstantiateSingletons() throws BeansException {
  // ......
  
  // 触发所有非延迟加载单例bean的初始化,主要步骤为getBean
  for (String beanName : beanNames) {
    // 合并父BeanDefinition对象
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
      if (isFactoryBean(beanName)) {
        // FactoryBean增加&前缀
        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
        if (bean instanceof FactoryBean) {
          FactoryBean<?> factory = (FactoryBean<?>) bean;
          boolean isEagerInit;
          if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
            isEagerInit = AccessController.doPrivileged(
                (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                getAccessControlContext());
          }
          else {
            isEagerInit = (factory instanceof SmartFactoryBean &&
                ((SmartFactoryBean<?>) factory).isEagerInit());
          }
          if (isEagerInit) {
            getBean(beanName);
          }
        }
      }
      else {
        // 实例化当前Bean
        getBean(beanName);
      }
    }
  }

  // ......
}

从getBean继续跟踪下去,我们会到了AbstractBeanFactory类的doGetBean⽅法,这个⽅法中的代码很多,我们直接找到核⼼部分:

// 创建单例bean
if (mbd.isSingleton()) {
  sharedInstance = getSingleton(beanName, () -> {
    try {
      // 创建bean
      return createBean(beanName, mbd, args);
    }
    catch (BeansException ex) {
      // Explicitly remove instance from singleton cache: It might have been put there
      // eagerly by the creation process, to allow for circular reference resolution.
      // Also remove any beans that received a temporary reference to the bean.
      destroySingleton(beanName);
      throw ex;
    }
  });
  beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

进入org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean方法,我们可以发现doCreateBean:

@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    throws BeanCreationException {

  // ......

  try {
    // 真正创建bean
    Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    if (logger.isTraceEnabled()) {
      logger.trace("Finished creating instance of bean '" + beanName + "'");
    }
    return beanInstance;
  }
  // ......
}

进⼊doCreateBean⽅法看看,该⽅法我们关注两块重点区域:

  • 创建Bean实例,此时尚未设置属性

    if (instanceWrapper == null) {
      // 创建Bean实例,仅调用构造方法,但尚未设置属性 (生命周期第一步)
      instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    
  • 给Bean填充属性,调⽤初始化⽅法,应⽤BeanPostProcessor后置处理器

    // 初始化bean实例
    Object exposedObject = bean;
    try {
      // bean属性填充
      populateBean(beanName, mbd, instanceWrapper);
      // 调用初始化方法,应用BeanPostProcessor后置处理器
      exposedObject = initializeBean(beanName, exposedObject, mbd);
    }
    

# lazy-init 延迟加载机制原理

普通 Bean 的初始化是在容器启动初始化阶段执⾏的,⽽被lazy-init=true修饰的 bean 则是在从容器⾥第⼀次进⾏context.getBean() 时进⾏触发。前面分析我们知道,Spring 启动的时候会把所有bean信息(包括XML和注解)解析转化成Spring能够识别的BeanDefinition并存到Hashmap⾥供下⾯的初始化时⽤,然后对每个BeanDefinition 进⾏处理,如果是懒加载的则在容器初始化阶段不处理,其他的则在容器初始化阶段进⾏初始化并依赖注⼊。

@Override
public void preInstantiateSingletons() throws BeansException {
  // ......
  
  // 触发所有非延迟加载单例bean的初始化,主要步骤为getBean
  for (String beanName : beanNames) {
    // 合并父BeanDefinition对象
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    // 容器初始化阶段,不处理懒加载
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
      if (isFactoryBean(beanName)) {
        // FactoryBean增加&前缀
        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
        if (bean instanceof FactoryBean) {
          FactoryBean<?> factory = (FactoryBean<?>) bean;
          boolean isEagerInit;
          if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
            isEagerInit = AccessController.doPrivileged(
                (PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
                getAccessControlContext());
          }
          else {
            isEagerInit = (factory instanceof SmartFactoryBean &&
                ((SmartFactoryBean<?>) factory).isEagerInit());
          }
          if (isEagerInit) {
            getBean(beanName);
          }
        }
      }
      else {
        // 实例化当前Bean
        getBean(beanName);
      }
    }
  }

  // ......
}

通过源码追踪,我们发现懒加载getBean时候最终是通过DefaultListableBeanFactory#resolveBean,最终又回到前面分析的getBean方法对bean进行实例化:

private <T> NamedBeanHolder<T> resolveNamedBean(
    String beanName, ResolvableType requiredType, @Nullable Object[] args) throws BeansException {
  // 懒加载最后,又调用了getBean
  Object bean = getBean(beanName, null, args);
  if (bean instanceof NullBean) {
    return null;
  }
  return new NamedBeanHolder<T>(beanName, adaptBeanInstance(beanName, bean, requiredType.toClass()));
}

总结:

  • 对于被修饰为lazy-init的bean,Spring容器初始化阶段不会进⾏init并且依赖注⼊,当第⼀次进⾏getBean时候才进⾏初始化并依赖注⼊,对于⾮懒加载的bean,getBean的时候会从缓存⾥头获取,因为容器初始化阶段 Bean 已经初始化完成并缓存了起来。

# Spring IoC循环依赖问题

# 什么是循环依赖

循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,最终形成闭环。⽐如A依赖于B,B依赖于C,C⼜依赖于A。注意,这⾥不是函数的循环调⽤,是对象的相互依赖关系。循环调⽤其实就是⼀个死循环,除⾮有终结条件。

cyclic_dependence

Spring中循环依赖场景有:

  • 构造器的循环依赖(构造器注⼊)
  • Field 属性的循环依赖(set注⼊)

其中,构造器的循环依赖问题⽆法解决,只能拋出 BeanCurrentlyInCreationException 异常,在解决属性循环依赖时,Spring采⽤的是三级缓存,提前暴露对象的⽅法。

# 循环依赖处理机制

  • 单例 bean 构造器参数循环依赖(⽆法解决)

  • prototype 原型 bean循环依赖(⽆法解决)

    对于原型bean的初始化过程中不论是通过构造器参数循环依赖还是通过setXxx⽅法产⽣循环依赖,Spring都会直接报错处理。

    AbstractBeanFactory.doGetBean()⽅法:

    if (isPrototypeCurrentlyInCreation(beanName)) {
     throw new BeanCurrentlyInCreationException(beanName);
    }
    
    protected boolean isPrototypeCurrentlyInCreation(String beanName) {
     Object curVal = this.prototypesCurrentlyInCreation.get();
     return (curVal != null &&
     (curVal.equals(beanName) || (curVal instanceof Set && ((Set<?>)
    curVal).contains(beanName))));
    }
    

    在获取bean之前如果这个原型bean正在被创建则直接抛出异常。原型bean在创建之前会进⾏标记这个beanName正在被创建,等创建结束之后会删除标记。

    try {
     //创建原型bean之前添加标记
     beforePrototypeCreation(beanName);
     //创建原型bean
     prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
     //创建原型bean之后删除标记
     afterPrototypeCreation(beanName);
    }
    

    总结:Spring 不⽀持原型 bean 的循环依赖。

  • 单例bean通过setXxx或者@Autowired进⾏循环依赖

    Spring 的循环依赖的理论依据基于 Java 的引⽤传递,当获得对象的引⽤时,对象的属性是可以延后设置的,但是构造器必须是在获取引⽤之前。Spring通过setXxx或者@Autowired⽅法解决循环依赖,其实是通过提前暴露⼀个ObjectFactory对象来完成的,简单来说就是ClassA在调⽤构造器完成对象初始化之后,在调⽤ClassA的setClassB⽅法之前就把ClassA实例化的对象通过ObjectFactory提前暴露到Spring容器中。

    Spring容器初始化ClassA通过构造器初始化对象后提前暴露到Spring容器, AbstractAutowireCapableBeanFactory#doCreateBean中关键代码:

    // 循环依赖处理,三级缓存
    boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
    if (earlySingletonExposure) {
       if (logger.isDebugEnabled()) {
         logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
       }
       //将初始化后的对象提前已ObjectFactory对象注⼊到容器中
       addSingletonFactory(beanName, new ObjectFactory<Object>() {
         @Override
         public Object getObject() throws BeansException {
           return getEarlyBeanReference(beanName, mbd, bean);
         }
       });
    }
    

    addSingletonFactory的方法:

    protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
      Assert.notNull(singletonFactory, "Singleton factory must not be null");
      synchronized (this.singletonObjects) {
        if (!this.singletonObjects.containsKey(beanName)) {
          // 暴露到三级缓存,singletonFactory 为lambda表达式
          this.singletonFactories.put(beanName, singletonFactory);
          this.earlySingletonObjects.remove(beanName);
          this.registeredSingletons.add(beanName);
        }
      }
    }
    

例如,ClassA和ClassB互相依赖,

  • ClassA调⽤setClassB⽅法,Spring⾸先尝试从容器中获取ClassB,此时ClassB不存在Spring容器中。
  • Spring容器初始化ClassB,同时也会将ClassB提前暴露到Spring容器中
  • ClassB调⽤setClassA⽅法,Spring从容器中获取ClassA ,因为第⼀步中已经提前暴露了ClassA,因此可以获取到ClassA实例
  • ClassA通过spring容器获取到ClassB,完成了对象初始化操作。

这样ClassA和ClassB都完成了对象初始化操作,解决了循环依赖问题。

cyclic_dependence_ab.png

上次更新: 8/11/2023, 12:49:40 AM
Spring AOP应用

Spring AOP应用→

最近更新
01
2025
01-15
02
Elasticsearch面试题
07-17
03
Elasticsearch进阶
07-16
更多文章>
Theme by Vdoing
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式