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

IOC图解设计结构

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

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

IOC源码分析

准备

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

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类

java 复制代码
public class UserService {
    public String hello() {
        return "Hello World! zayton!";
    }
}

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

java 复制代码
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. 初始化容器
java 复制代码
public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		//初始化资源解析器和父容器
		super(parent);
		//设置配置文件路径
		setConfigLocations(configLocations);
		//初始化容器
		if (refresh) {
			refresh();
		}
	}

初始化容器(重要)

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

java 复制代码
	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()方法,它首先会刷新容器,然后返回一个新的容器,具体步骤如下所示。

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

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

java 复制代码
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配置文件。

java 复制代码
	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

java 复制代码
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实现。

java 复制代码
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方法

java 复制代码
	public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		doRegisterBeanDefinitions(doc.getDocumentElement());
	}

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

java 复制代码
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定义信息

java 复制代码
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定义信息,然后注册到容器中。

java 复制代码
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中

java 复制代码
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中

java 复制代码
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,搁这互相套娃呢? 那么它具体是怎么解决循环依赖的呢?循环依赖无非是双方都需要对象类信息而已,我们在创建AService时发现需要BService,完全可以将半成品的AService方到缓存中,然后创建BService,让BService拿着缓存中的AService先完成创建,然后回到AService这边继续完成后续工作。 为此Spring为了解决单例循环依赖而设置了三级缓存,代码如下:

java 复制代码
/** 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,就是从三级缓存查找

java 复制代码
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从以下代码开始。

java 复制代码
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的特性,是为了后置处理。

java 复制代码
	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时,会遇到下面这段代码。

java 复制代码
//当前多例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),如下所示:

java 复制代码
// 源码位于 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的核心功能之一:依赖注入,包括自动注入@Autowired注入(通过类型方式注入)@Resource注入(通过名称注入)等,Spring会根据bean的注入模型(默认不自动注入),选择根据名称自动注入还是根据类型自动注入。然后调用InstantiationAwareBeanPostProcessor#postProcessProperties()完成@Autowired和@Resource的属性注入。

java 复制代码
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
java 复制代码
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的销毁。

java 复制代码
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 的生命周期流程

参考文献

javadoop.com/post/spring...

www.pdai.tech/md/spring/s...

zhuanlan.zhihu.com/p/223028634

juejin.cn/post/715588...

相关推荐
程序员大金1 小时前
基于SSM+Vue+MySQL的酒店管理系统
前端·vue.js·后端·mysql·spring·tomcat·mybatis
努力的布布1 小时前
Spring源码-从源码层面讲解声明式事务的运行流程
java·spring
程序员大金2 小时前
基于SpringBoot的旅游管理系统
java·vue.js·spring boot·后端·mysql·spring·旅游
爱上语文2 小时前
Springboot三层架构
java·开发语言·spring boot·spring·架构
你知道“铁甲小宝”吗丶3 小时前
【第33章】Spring Cloud之SkyWalking服务链路追踪
java·spring boot·spring·spring cloud·skywalking
听封4 小时前
Thymeleaf 的创建
java·spring boot·spring·maven
huapiaoy5 小时前
Spring mvc
java·spring·mvc
你知道“铁甲小宝”吗丶5 小时前
【第34章】Spring Cloud之SkyWalking分布式日志
java·spring boot·spring·spring cloud·skywalking
一颗知足的心8 小时前
SpringCloud Alibaba五大组件之——Sentinel
spring·spring cloud·sentinel