Spring入门心经之第一章 IOC详解

IOC图解设计结构

这里我们就对Spring的IOC的核心过程展开探讨,整体过程就如下图所示,其过程为:

  1. 加载Bean的配置(比如xml配置)
  2. 根据Bean的定义加载生成Bean的实例
  3. 然后将bean实例存入到bean容器中
  4. 后续上下文需要加载,则从bean容器中获取Spring入门心经之第一章 IOC详解

IOC源码分析

准备

为了解析源码,我们首先需要配置配置文件spring-config.xml。

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


     <bean id="userService" class="com.example.springboot.spring.ioc.UserService"></bean>

</beans>

编写一个UserService类

public class UserService {
    public String hello() {
        return "Hello World! zayton!";
    }
}

编写一个测试案例,然后debug进入源码开始阅读;由于源码复杂度高,所以我们主要讲解核心步骤。

public class Entrance {
    /**
     * 基于配置文件的依赖注入测试
     *
     * @param args
     */

    public static void main(String[] args) {

        ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        // retrieve configured instance
        UserService userService = context.getBean("userService", UserService.class);
        // use configured instance
        try {
            userService.hello();
        } catch (Exception e) {
            // e.printStackTrace();
        }

    }
}

从ClassPathXmlApplicationContext看IOC的整体流程

主要做了以下几个步骤:

  1. 初始化资源解析器和父容器
  2. 设置配置文件路径
  3. 初始化容器
public ClassPathXmlApplicationContext(
   String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

   throws BeansException 
{
  //初始化资源解析器和父容器
  super(parent);
  //设置配置文件路径
  setConfigLocations(configLocations);
  //初始化容器
  if (refresh) {
   refresh();
  }
 }

初始化容器(重要)

IOC容器对bean定义资源的载入是从refresh()函数开始的,主要作用是:在创建IOC容器前,如果存在容器,需要将就容器销毁和关闭,然后建立新的容器,对新容器进行初始化,将bean定义资源加载到新容器。

 public void refresh() throws BeansException, IllegalStateException {
   // 来个锁,不然 refresh() 还没结束,你又来个启动或销毁容器的操作,那不就乱套了嘛
  synchronized (this.startupShutdownMonitor) {
   StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

   // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
   prepareRefresh();

   // 这步比较关键,这步完成后,配置文件就会解析成一个个 Bean 定义,注册到 BeanFactory 中,
       // 当然,这里说的 Bean 还没有初始化,只是配置信息都提取出来了,
      // 注册也只是将这些信息都保存到了注册中心(说到底核心是一个 beanName-> beanDefinition 的 map)
   ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

   // 设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
   prepareBeanFactory(beanFactory);

   try {
    // 允许子类扩展
    postProcessBeanFactory(beanFactory);

    StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
    // 调用 BeanFactoryPostProcessor 各个实现类的 postProcessBeanFactory(factory) 回调方法
    invokeBeanFactoryPostProcessors(beanFactory);

    // Register bean processors that intercept bean creation.
    registerBeanPostProcessors(beanFactory);
    beanPostProcess.end();

    // 初始化当前ApplicationContext 国际化。
    initMessageSource();

    // 初始化当前ApplicationContext 的事件广播器
    initApplicationEventMulticaster();

    // 钩子方法,具体的子类可以在这里初始化一些特殊的 Bean
    onRefresh();

    // 注册事件监听器
    registerListeners();

    // 初始化所有的 singleton beans(除了lazy-init)
    finishBeanFactoryInitialization(beanFactory);

    //  初始化完成
    finishRefresh();
   }

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

    // 销毁已创建的单例的Beans
    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之obtainFreshBeanFactory

我们先看obtainFreshBeanFactory()方法,它首先会刷新容器,然后返回一个新的容器,具体步骤如下所示。

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
  //销毁并关闭旧的beanFactory,创建新的beanFactory
  refreshBeanFactory();
  //返回刚刚创建的beanFactory
  return getBeanFactory();
 }

在refreshBeanFactory()方法中,它主要做的事情是先销毁容器,然后创建一个DefaultListableBeanFactory的beanFactory,然后将bean定义信息(BeanDefinition)加载到这个beanFactory中。然后将beanFactory设置为当前创建的DefaultListableBeanFactory

protected final void refreshBeanFactory() throws BeansException {
     // 如果ApplicationContext中已经加载过BeanFactory了,销毁所有Bean,关闭BeanFactory
  if (hasBeanFactory()) {
   destroyBeans();
   closeBeanFactory();
  }
  try {
  //创建一个DefaultListableBeanFactory 
   DefaultListableBeanFactory beanFactory = createBeanFactory();
   beanFactory.setSerializationId(getId());
   // 设置 BeanFactory 的两个配置属性:是否允许 Bean 覆盖、是否允许循环引用
   customizeBeanFactory(beanFactory);
   // 加载 Bean 到 BeanFactory 中
   loadBeanDefinitions(beanFactory);
   this.beanFactory = beanFactory;
  }
  catch (IOException ex) {
   throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
  }
 }

初始化Beanfactory之loadBeanDefinitions

loadBeanDefinitions主要是创建了BeanDefinition读取器,然后用这个读取器加载BeanDefinition,通过这个读取器加载XML配置方式中的bean定义资源和构造函数里配置的bean配置文件。

 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
  // 创建XmlBeanDefinitionReader,即bean读取器
  XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

  // 配置环境、资源加载、解析器
  beanDefinitionReader.setEnvironment(this.getEnvironment());
  beanDefinitionReader.setResourceLoader(this);
  beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

  //初始化 BeanDefinitionReader(提供给子类覆写)
  initBeanDefinitionReader(beanDefinitionReader);
  //加载BeanDefinition
  loadBeanDefinitions(beanDefinitionReader);
 }
 
 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
  //加载xml配置方式中的bean定义的资源
  Resource[] configResources = getConfigResources();
  if (configResources != null) {
   reader.loadBeanDefinitions(configResources);
  }
  //加载构造函数方式中的xml配置的资源
  String[] configLocations = getConfigLocations();
  if (configLocations != null) {
   reader.loadBeanDefinitions(configLocations);
  }
 }

具体加载loadBeanDefinitions的过程

由于上面我们使用ClassPathXmlApplicationContext作为例子分析,因此上述步骤程序只会执行reader.loadBeanDefinitions(configLocations);分支。获取到一个resource数组,我们可以拿着resources这个配置信息数组去加载BeanDefinition

public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
  //忽略细节
  //模式匹配类型的解析器,这种方式是加载多个满足匹配条件的资源
  if (resourceLoader instanceof ResourcePatternResolver) {
    //忽略细节
   try {
    // 获取到要加载的资源
    Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
    //返回加载到的个数
    int count = loadBeanDefinitions(resources);
    //忽略细节
  }
  else {
    //忽略细节
  }
 }

Spring将Bean定义资源转换为Document对象

我们继续深入源码,会发现在XmlBeanDefinitionReader类中可以看到doLoadBeanDefinitions()方法,这个方法主要作用是载入Bean定义资源文件,然后将Bean定义资源转换为Document对象,具体过程由documentLoader实现。

public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
        ErrorHandler errorHandler, int validationMode, boolean namespaceAware)
 throws Exception 
{

    // 创建文件解析器工厂
    DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
    if (logger.isTraceEnabled()) {
        logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
    }
    // 创建文档解析器
    DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
    return builder.parse(inputSource); // 解析
}

protected DocumentBuilderFactory createDocumentBuilderFactory(int validationMode, boolean namespaceAware)
        throws ParserConfigurationException 
{

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(namespaceAware);

    // 设置解析XML的校验
    if (validationMode != XmlValidationModeDetector.VALIDATION_NONE) {
        factory.setValidating(true);
        if (validationMode == XmlValidationModeDetector.VALIDATION_XSD) {
            // Enforce namespace aware for XSD...
            factory.setNamespaceAware(true);
            try {
                factory.setAttribute(SCHEMA_LANGUAGE_ATTRIBUTE, XSD_SCHEMA_LANGUAGE);
            }
            catch (IllegalArgumentException ex) {
                ParserConfigurationException pcex = new ParserConfigurationException(
                        "Unable to validate using XSD: Your JAXP provider [" + factory +
                        "] does not support XML Schema. Are you running on Java 1.4 with Apache Crimson? " +
                        "Upgrade to Apache Xerces (or Java 1.5) for full XSD support.");
                pcex.initCause(ex);
                throw pcex;
            }
        }
    }

    return factory;
}

Spring如何基于Document进行对象解析

首先通过document对象获取document元素,然后调用doRegisterBeanDefinitions方法

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

这时候基于这个配置文件的内容,将这些字符串的信息生成数据转为BeanDefinition

protected void doRegisterBeanDefinitions(Element root) {
  BeanDefinitionParserDelegate parent = this.delegate;
  this.delegate = createDelegate(getReaderContext(), root, parent);
  //忽略....

  preProcessXml(root);
  // 主要调用这个方法,从Document的根元素开始进行Bean定义的Document对象  
  parseBeanDefinitions(root, this.delegate);
  postProcessXml(root);

  this.delegate = parent;
 }

再parseBeanDefinitions()方法中会调用parseDefaultElement(),将xml为bean的标签数据取出来生成bean定义信息

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>元素, 按照Spring的Bean规则解析元素  
    else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
        processBeanDefinition(ele, delegate);
    }
    // 如果元素节点<Beans>元素,即它是嵌套类型的
    else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
        // 递归解析
        doRegisterBeanDefinitions(ele);
    }
}

元素节点元素转为BeanDefinition的细节

将bean标签生成BeanDefinition然后存入BeanDefinitionHolder中。通过BeanDefinitionHolder加载bean定义信息,然后注册到容器中。

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if (bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
        try {
            // 注册最终的装饰实例,这是BeanDefinition向IOC容器注册的入口
           BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
        }
        catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" +
                    bdHolder.getBeanName() + "'", ele, ex);
        }
        // 完成BeanDefinition注册后,向容器发送注册完成事件
        getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}

将bean注册到IOC容器

上文说过通过BeanDefinitionHolder获取bean信息,而后调用registerBeanDefinition将bean注册到IOC中

public static void registerBeanDefinition(
   BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

   throws BeanDefinitionStoreException 
{

  // 将beandefinition及其名字注册到容器里
  String beanName = definitionHolder.getBeanName();
  registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

  // 如果存在别名则逐个注册进容器
  String[] aliases = definitionHolder.getAliases();
  if (aliases != null) {
   for (String alias : aliases) {
    registry.registerAlias(beanName, alias);
   }
  }
 }

IOC容器本质上就是一个beanDefinitionMap,然后将BeanDefinition put到map中


private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);


@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException 
{

    //忽略....

    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    // 如果已经注册
    if (existingDefinition != null) {
        // 检查是否可以覆盖
        if (!isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
        }
       //忽略....

        // 覆盖
        this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else {
       //忽略....

        //重置所有已经注册过的BeanDefinition的缓存  
        this.frozenBeanDefinitionNames = null;
    }

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

IOC常见问题

Spring是如何解决循环依赖的呢?

循环依赖说白了就是需要我中有你,你中有我,最后谁都不愿成全对方;就如下图所示,想要创建AService就得先拥有BService,可BService的创建却又需要AService,搁这互相套娃呢?Spring入门心经之第一章 IOC详解那么它具体是怎么解决循环依赖的呢?循环依赖无非是双方都需要对象类信息而已,我们在创建AService时发现需要BService,完全可以将半成品的AService方到缓存中,然后创建BService,让BService拿着缓存中的AService先完成创建,然后回到AService这边继续完成后续工作。为此Spring为了解决单例循环依赖而设置了三级缓存,代码如下:

/** Cache of singleton objects: bean name --> bean instance */
//存的是完整的单例对象
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
 
/** Cache of early singleton objects: bean name --> bean instance */
//存的是半成品单例对象
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

/** Cache of singleton factories: bean name --> ObjectFactory */
//单例工厂的缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

我们首先从缓存中尝试获取bean,就是从三级缓存查找

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // Spring首先从singletonObjects(一级缓存)中尝试获取
    Object singletonObject = this.singletonObjects.get(beanName);
    //判断当前单例bean是否正在创建中
    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;
}

如果缓存中都没有,那么就需要创建bean,创建bean从以下代码开始。

if (mbd.isSingleton()) {
 sharedInstance = getSingleton(beanName, () -> {
   try {
    return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
    destroySingleton(beanName);
    throw ex;
   }
  });
 beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

上述创建bean的代码主要步骤如下:

  1. 调用createBean方法,在方法内部的doCreateBean(),通过createBeanInstance创建一个原始对象。
  2. 调用addSingletonFactory()添加bean 工厂对象到singletonFactories缓存。
  3. 调用populateBean方法向原始 bean 对象中填充属性,并解析依赖。
  4. 最后getSingleton中通过singletonFactory.getObject()创建singletonObject,最后调用addSingleton将完整的bean对象存入到singletonObjects(一级缓存)中。

二级缓存是否可以解决循环依赖问题

到这里可能会有人疑惑二级缓存貌似就可以解决循环依赖问题,为什么还需要三级缓存呢?三级缓存的目的主要是为了解决AOP的特性,是为了后置处理。

 protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
  Object exposedObject = bean;
  if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
   for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
    // 这么一大段就这句话是核心,也就是当bean要进行提前曝光时,
                // 给一个机会,通过重写后置处理器的getEarlyBeanReference方法,来自定义操作bean
                // 值得注意的是,如果提前曝光了,但是没有被提前引用,则该后置处理器并不生效!!!
                // 这也正式三级缓存存在的意义,否则二级缓存就可以解决循环依赖的问题
    exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
   }
  }
  return exposedObject;
 }

Spring为何不能解决非单例属性之外的循环依赖

prototype情况

假设我们遇到循环依赖的bean是多例的,我们在AService创建得不到BService再到BService创建得不到AService时,去创建AService时,会遇到下面这段代码。

//当前多例bean处于创建中,说明存在循环依赖,直接报错
if (isPrototypeCurrentlyInCreation(beanName)) {
 throw new BeanCurrentlyInCreationException(beanName);
}

构造器循环依赖

构造器注入形成的循环依赖:也就是AService需要在BService的构造函数中完成初始化,BService也需要在AService的构造函数中完成初始化。而Spring解决循环依赖依靠的是Bean的“中间态”这个概念,而这个中间态指的是已经实例化,但还没初始化的状态。实例化的过程又是通过构造器创建的,如果AService还没创建好出来,怎么可能提前曝光。循环依赖难以解决。

Spring bean生命周期

生命周期大致分为几个阶段:创建->属性填充->初始化bean->使用->销毁。我们简单介绍下这些阶段所做的事:

  1. 创建阶段主要实例化bean。
  2. 属性填充阶段主要是依赖注入,将当前对象依赖的bean对象,从容器中找出填充到对应的属性中。
  3. 初始化bean阶段包括回调各种aware接口、回调各种初始化方法、生成AOP对象。
  4. 使用阶段则是bean创建完成,提供服务的阶段。
  5. 销毁阶段,主要是对bean进行销毁。

创建bean

首先Spring是通过反射来创建对象的,不过如果我们提供了Supplier或者工厂方法,Spring也会直接使用我们提供的创建方法。第一阶段实例化bean在源码中的doCreateBean方法中createBeanInstance(beanName, mbd, args),如下所示:


// 源码位于 AbstractAutowireCapableBeanFactory.java

if (instanceWrapper == null) {
 //instanceWrapper 即实例化后的对象
 //mbd 这里面包含这个类的所有实例化需要的信息
 instanceWrapper = createBeanInstance(beanName, mbd, args);
}

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
   // 再次解析BeanDefinition的class,确保class已经被解析
   Class<?> beanClass = resolveBeanClass(mbd, beanName);

   // 1: 如果提供了Supplier,通过Supplier产生对象
   Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
      return obtainFromSupplier(instanceSupplier, beanName);
   }

   // 2: 如果有工厂方法,使用工厂方法产生对象
   // 在@Configration配置@Bean的方法,也会被解析为FactoryMethod
   if (mbd.getFactoryMethodName() != null) {
      return instantiateUsingFactoryMethod(beanName, mbd, args);
   }
   //...省略部分代码
   // 3: 推断构造方法
   // 3.1 执行后置处理器,获取候选构造方法
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   // 3.2 需要自动注入的情况
   if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
         mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
      return autowireConstructor(beanName, mbd, ctors, args);
   }

   // 3.3 默认使用没有参数的构造方法
   return instantiateBean(beanName, mbd);
}

根据源码分析,我们可以把上述代码分为几个步骤:

  1. 判断是否提供了supplier,如果提供则通过supplier产生对象
  2. 判断是否提供了工厂方法,如果提供则通过工厂方法产生对象
  3. 如果都没有则判断构造方法有几个,若只有一个则直接使用该构造方法
  4. 若有多个构造方法,会判断有没有加了Autowired注解的构造参数,若都没有则使用无参构造;若有且是加了@Autowired(required=true)注解的构造方法则使用该方法;若只有加Autowired的构造方法,则会从所有加了Autowired的构造方法中综合打分,选择一个匹配参数最多,类型最准确的构造方法。
Spring入门心经之第一章 IOC详解
在这里插入图片描述

属性填充

该阶段是Spring的核心功能之一:依赖注入,包括自动注入@Autowired注入(通过类型方式注入)@Resource注入(通过名称注入)等,Spring会根据bean的注入模型(默认不自动注入),选择根据名称自动注入还是根据类型自动注入。然后调用InstantiationAwareBeanPostProcessor#postProcessProperties()完成@Autowired和@Resource的属性注入。

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   // 省略部分代码
   // 获取bean的注入类型
   int resolvedAutowireMode = mbd.getResolvedAutowireMode();
   // 1: 自动注入
   if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
      MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
      // Add property values based on autowire by name if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
         // 根据名称注入
         autowireByName(beanName, mbd, bw, newPvs);
      }
      // Add property values based on autowire by type if applicable.
      if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
         // 根据类型注入
         autowireByType(beanName, mbd, bw, newPvs);
      }
      pvs = newPvs;
   }

   // 2: 调用BeanPostProcessor,完成@Autowired @Resource属性填充
   PropertyDescriptor[] filteredPds = null;
   if (hasInstAwareBpps) {
      if (pvs == null) {
         pvs = mbd.getPropertyValues();
      }
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;

            // 重点: 完成@Autowired @Resource属性填充
            PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
            if (pvsToUse == null) {
               if (filteredPds == null) {
                  // 需要注入的属性,会过滤掉Aware接口包含的属性(通过ignoreDependencyInterface添加)
                  filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
               }
               pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
               if (pvsToUse == null) {
                  return;
               }
            }
            pvs = pvsToUse;
         }
      }
   }
  
    // 3: 依赖检查
   if (needsDepCheck) {
      if (filteredPds == null) {
         filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
      }
      checkDependencies(beanName, mbd, filteredPds, pvs);
   }
   // 4: 将属性应用到bean中
   if (pvs != null) {
      applyPropertyValues(beanName, mbd, bw, pvs);
   }
}

初始化bean

该阶段包含比较多的步骤,整体大致分为:

  1. 检查当前创建的bean是否有实现xxAware相关的接口,如果有则调用用户的实现
  2. 如果有没有继承BeanPostProcessor则会调用用户实现BeanPostProcessorpostProcessBeforeInitialization
  3. 然后看看bean有没有继承InitializingBean接口,如果有则调用afterPropertiesSet方法
  4. 如果用户配置init-method方法则调用这个方法
  5. 然后调用BeanPostProcessorpostProcessAfterInitialization
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
  // 
  // 如果bean实现了BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口则回调
  invokeAwareMethods(beanName, bean);

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // ApplicationContextAwareProcessor: 其他Aware方法的回调
      // InitDestroyAnnotationBeanPostProcessor: @PostConstruct方法的回调
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      // 处理bean中定义的init-method和@bean(initMethod)的init方法回调
      //或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 
      invokeInitMethods(beanName, wrappedBean, mbd);
   }

   // 调用after方法
   // 重点: AOP生成代理对象
   if (mbd == null || !mbd.isSynthetic()) {
    // BeanPostProcessor 的 postProcessAfterInitialization 回调
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}

初始化完成后,bean就会被放入单例池中,如果后续有使用该bean的地方,则直接从单例池中获取,不会再次创建bean(仅限单例)。

bean的销毁阶段

在创建bean的时候,会判断如果bean是DisposableBean、AutoCloseable的子类,或者有 destroy-method等,会注册为可销毁的bean,在容器关闭时,调用对应的方法进行bean的销毁。

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
      throws BeanCreationException 
{
   // ...省略代码
   try {
      // 为bean注册DisposableBean,在容器关闭时,调用destory()
      registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
      throw new BeanCreationException(
            mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }

   return exposedObject;
}

总结成一张图就是如下所示,Spring 容器中Bean 的生命周期流程Spring入门心经之第一章 IOC详解

参考文献

[Spring IOC 容器源码分析]https://javadoop.com/post/spring-ioc 

[Spring进阶- Spring IOC实现原理详解之IOC初始化流程]https://www.pdai.tech/md/spring/spring-x-framework-ioc-source-2.html

[烂大街的 Spring 循环依赖问题,你真以为自己会了吗?]https://zhuanlan.zhihu.com/p/223028634 

[聊透Spring bean的生命周期]https://juejin.cn/post/7155884227714613285?searchId=2023080117131985BA48BA99B03F054099#heading-0


原文始发于微信公众号(写代码的ZaytonSquid):Spring入门心经之第一章 IOC详解

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/246263.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!