Spring 系列——IOC容器初始化

Spring最核心的两个模块就是IOC(控制反转)和AOP(面向切面编程)。本篇文章将从源码的角度来分析一下Spring IOC容器初始化的过程,篇幅较长,需要花点时间阅读
如果文章中有描述错误或者不合理的地方,欢迎指正!

源码版本:5.2.7.RELEASE

前言

我们先看下启动Spring容器最基本的例子,

public static void main(String[] args) {
    // 通过spring.xml文件来启动一个容器
    ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
    // 从容器中获取Bean实例
    Person person = (Person) context.getBean("person");
	System.out.println(person.getUserName());
}
==========执行结果========
muskmelon

spring.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="person" class="com.muskmelon.domain.Person">
        <property name="userName" value="muskmelon"/>
    </bean>
</beans>

以上代码利用配置文件spring.xml来启动一个容器,需要引入spring相关的依赖,这里引入spring-context即可

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.7.RELEASE</version>
</dependency>

spring-context包含了spring-beansspring-corespring-aopspring-expressspring-jcl这几个核心的包

代码很好理解,我们通过ClassPathXmlApplicationContext类来启动容器。读取xml配置,根据xml配置文件内容创建ApplicationContext。我们先看一下ClassPathXmlApplicationContext的继承结构
在这里插入图片描述
我们可以看到ClassPathXmlApplicationContext经过多个好几个抽象类才到ApplicationContext,除了ClassPathXmlApplicationContext之外,还有FileSystemXmlApplicationContextAnnotationConfigApplicationContext能创建容器

  • ClassPathXmlApplicationContext:从classpath读取配置文件
  • FileSystemXmlApplicationContext:从系统路径读取配置文件
  • AnnotationConfigApplicationContext:基于注解使用,采用java配置类和各种注解来配置,熟悉的朋友应该知道 @Configuration

本文为了方便理解整个容器构建流程,所以使用ClassPathXmlApplicationContext进行分析
文章开头的例子中,第一行代码就是用来创建容器的,我们一起来深入研究一下容器的启动过程。在介绍容器启动过程之前,我们先来了解一下两个比较关键的术语:BeanFactoryBeanDefinition

BeanFactory

BeanFactory,从字面意思上理解为生产Bean的工厂,负责生产和管理Bean实例。
也许有人会有疑问,这个BeanFactory也是容器吗,和前面的ApplicationContext有什么关系?源码注释中有这么一句话:

The root interface for accessing a Spring bean container

表示BeanFactory是Spring容器最顶层的接口,再看一下继承结构
在这里插入图片描述
BeanFactory主要有三个实现接口ListableBeanFactoryHierarchicalBeanFactoryAutowireCapableBeanFactory,主要用途分别如下:

  • ListableBeanFactory:提供了获取多个Bean的方法,从源码中能看到,BeanFactory只提供了获取单个Bean的方法
  • HierarchicalBeanFactory:父子级联 IoC 容器的接口,子容器可以通过接口方法访问父容器; 通过 HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean,但父容器不能访问子容器的 Bean
  • AutowireCapableBeanFactory:定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法

上面的ApplicationContext实现了ListableBeanFactoryHierarchicalBeanFactory两个接口,并没有实现AutoworeCapableBeanFactory;没用继承,可以用组合,从ApplicationContext源码中最后一个方法 getAutowireCapableBeanFactory()中能看到。
还有一个类比较特殊:DefaultListableBeanFactory,它继承了BeanFactory下的三个子类,这里先提一下,后面分析源码中会提到。
BeanFactory源码

public interface BeanFactory {
	/**
	 * 工厂实例标识符
	 * 如果一个beanName叫‘myJndiObject’,是一个容器工厂Bean,在beanName名称前加上&标识符,通过get("&myJndiObject")会获取到这个工厂,而不是这个工厂的实例
	 */
	String FACTORY_BEAN_PREFIX = "&";
	
	/**
	 * 通过beanName获取Bean实例
	 */
	Object getBean(String name) throws BeansException;

	/**
	 * 根据beanName和类型,获取Bean实例
	 */
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	/**
	 * 根据beanName获取实例,args为实例构造函数的参数
	 */
	Object getBean(String name, Object... args) throws BeansException;

	/**
	 * 通过类型获取Bean实例
	 */
	<T> T getBean(Class<T> requiredType) throws BeansException;

	/**
	 * 通过类型获取Bean实例,args为实例构造函数的参数
	 */
	<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;

	/**
	 * 不知道干什么的,用的较少,想了解的可以自行查阅资料
	 */
	<T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);

	/**
	 * 不知道干什么的,用的较少,想了解的可以自行查阅资料
	 */
	<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);

	/**
	 * 容器中是否包含该beanName的实例
	 */
	boolean containsBean(String name);

	/**
	 * 判断该beanName的实例是否为单例,如果找不到该bean,抛出NoSuchBeanDefinitionException异常
	 */
	boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 判断该beanName的实例是否为多例,如果找不到该bean,抛出NoSuchBeanDefinitionException异常
	 */
	boolean isPrototype(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 判断bean类型是否匹配
	 */
	boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 判断bean类型是否匹配
	 */
	boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;

	/**
	 * 获取bean类型
	 */
	@Nullable
	Class<?> getType(String name) throws NoSuchBeanDefinitionException;

	/**
	 * 获取bean实例
	 */
	@Nullable
	Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;

	/**
	 * 获取bean的别名
	 */
	String[] getAliases(String name);
}

BeanDefinition

当我们从配置文件中解析Bean之后,Bean的属性信息就是存在这个BeanDefinition中,这仅仅只是Bean的定义,并不是实例化后的数据。下面我们通过源码看看容器中到底定义了Bean哪些信息。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	// 单例标识
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

	// 多例标识
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

	int ROLE_APPLICATION = 0;
	int ROLE_SUPPORT = 1;
	int ROLE_INFRASTRUCTURE = 2;
	
	// Modifiable attributes

	// 设置父类
	void setParentName(@Nullable String parentName);

	@Nullable
	String getParentName();

	// 设置bean的class名称
	void setBeanClassName(@Nullable String beanClassName);

	@Nullable
	String getBeanClassName();

	// 设置作用域
	void setScope(@Nullable String scope);

	@Nullable
	String getScope();

	// 设置bean是否懒加载
	void setLazyInit(boolean lazyInit);

	boolean isLazyInit();

	// 设置Bean依赖的所有Bean,注意,这里的依赖不是指属性依赖(如@Autowire标记)
	// 是 depends-on="" 属性设置的值
	void setDependsOn(@Nullable String... dependsOn);

	@Nullable
	String[] getDependsOn();

	// 设置bean是否可以注入到其他Bean中,只对根据类型注入有效
	void setAutowireCandidate(boolean autowireCandidate);

	boolean isAutowireCandidate();

	// 同一接口的多个实现,如果不指定名字的话,Spring会优先选择设置primary为true的Bean
	void setPrimary(boolean primary);

	boolean isPrimary();

	// 设置工厂名称
	void setFactoryBeanName(@Nullable String factoryBeanName);
	
	@Nullable
	String getFactoryBeanName();

	// 指定工厂类的工厂方法名称
	void setFactoryMethodName(@Nullable String factoryMethodName);

	@Nullable
	String getFactoryMethodName();

	// 构造器参数
	ConstructorArgumentValues getConstructorArgumentValues();

	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}
	
	 // Bean中的属性值 
	MutablePropertyValues getPropertyValues();

	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	// 设置初始化方法
	void setInitMethodName(@Nullable String initMethodName);

	@Nullable
	String getInitMethodName();

	// 设置销毁方法
	void setDestroyMethodName(@Nullable String destroyMethodName);

	@Nullable
	String getDestroyMethodName();

	void setRole(int role);

	int getRole();

	void setDescription(@Nullable String description);

	@Nullable
	String getDescription();
	
	// Read-only attributes
	
	ResolvableType getResolvableType();

	// 是否单例
	boolean isSingleton();

	// 是否多例
	boolean isPrototype();

	// 是否抽象,如果bean被设置为abstract,那么不能被实例化
	boolean isAbstract();

	@Nullable
	String getResourceDescription();

	@Nullable
	BeanDefinition getOriginatingBeanDefinition();
}

了解主要的两个术语BeanFactoryBeanDefinition之后,接下来我们去看看容器启动的过程究竟是发生了什么

容器启动步骤

我们先从宏观的角度看一下Spring容器,配置文件,应用程序之间的联系,看下图:
在这里插入图片描述
容器启动主要有3个步骤

  • 读取并解析配置文件,生成BeanDefinition
  • 根据Bean定义进行实例化
  • 将实例化好的Bean注册到容器中

结合代码,首先我们看一下ClassPathXmlApplicationContext的构造方法

public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
	
	public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
		this(new String[] {configLocation}, true, null);
	}
	
	public ClassPathXmlApplicationContext(
			String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
			throws BeansException {
		
		super(parent);
		// 解析路径
		setConfigLocations(configLocations);
		if (refresh) {
			// ★核心方法★
			refresh();
		}
	}
	
	...
}

容器启动时,最核心的方法就是refresh

方法所在位置:517行org.springframework.context.support.AbstractApplicationContext#refresh

refresh方法

public void refresh() throws BeansException, IllegalStateException {
	// 加个锁,容器在启动过程中,不允许再次启动或销毁
	synchronized (this.startupShutdownMonitor) {
		// 做一些准备工作,记录容器启动时间,设置启动激活标识
		prepareRefresh();
	
		// 【重点】读取配置文件,解析成BeanDefinition,注册到容器中(存储到一个Map<beanName,BeanDefinition>中)
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
	
		// 设置bean的类加载器,注册特殊的bean,添加BeanPostProcessor
		prepareBeanFactory(beanFactory);
	
		// ↑ 执行完上面三步,所有的Bean都加载注册完成,但还未实例化
		try {
			// 子类扩展实现
			postProcessBeanFactory(beanFactory);
	
			// 调用BeanFactoryPostProcessor各个实现类的postProcessBeanFactory方法
			invokeBeanFactoryPostProcessors(beanFactory);
	
			// 注册BeanPostProcessor的实现类
			// 接口提供两个方法:postProcessBeforeInitialization 和 postProcessAfterInitialization
			// 这两个方法分别在初始化前后执行
			registerBeanPostProcessors(beanFactory);
	
			// 初始化国际化资源
			initMessageSource();
	
			// 初始化事件广播器
			initApplicationEventMulticaster();
	
			// 模板方法,提供给子类实现,子类可以在这里注册一些特殊的bean
			onRefresh();
	
			// 添加并注册监听器
			registerListeners();
	
			// 【重点】实例化所有非懒加载的单例
			finishBeanFactoryInitialization(beanFactory);
	
			// 广播事件,容器初始化完成
			finishRefresh();
		}
	
		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}
	
			// 销毁已初始化的单例bean,避免资源浪费
			destroyBeans();
	
			// 重置容器激活标识
			cancelRefresh(ex);
	
			// 抛出异常
			throw ex;
		}
	
		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

下面我们对refresh中几个重要的方法进行讲解

【重点】obtainFreshBeanFactory

这个方法中主要完成了下面几件事:读取配置,解析成BeanDefinition,注册到容器
我们看下面这张调用链图,从读取配置到注册到容器经历了一系列的过程。
在这里插入图片描述

读取配置文件

我们看到调用链中有很多loadBeanDefinitions方法,Spring中提供了ResourceLoader类,基于策略模式去读取xml文件,构造Resource对象(限于文章篇幅,读取xml文件这块逻辑本文不再展开),有了Resource后,我们看doLoadBeanDefinitions中有行代码,用于把xml文件解析Document对象

Document doc = doLoadDocument(inputSource, resource);

390行
org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions

解析成 BeanDefinition

在在下面代码中,我们看到Spring提供了两种命名空间节点解析的方式parseDefaultElementparseCustomElement,有什么区别呢,往下看

// 168行
// org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#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);
	}
}

(1) parseCustomElement (不是本章重点,不展开)
parseCustomElement 用来处理自定义命名空间节点,例如:<context:component-scan/><aop:aspectj-autoproxy/>

(2) parseDefaultElement

// 189行
// org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#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);
	}
}

parseDefaultElement用来处理默认命名空间节点,有以下4个:importaliasbeanbeans
主要看一下对bean标签的处理,也就是将xml中类似这样一段<bean id="person" class="com.dev.domain.Person"/>的标签解析成BeanDefinition,接着看

// 305行
// org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 1.将<bean/>标签中的信息提取出来,封装到BeanDefinitionHolder中
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	// 2.下面的先忽略,后面再讲
	if (bdHolder != null) {
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// Register the final decorated instance.
			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));
	}
}

第一行将<bean/>标签中的信息提取出来,封装到BeanDefinitionHolder中,在讲怎么解析前,我们看一下<bean/>标签中可以定义哪些属性

Property说明
Name可以指定id,name(用逗号,分号,空格分隔)
Class类的全限定名
Scope作用域
Constructor arguments构造函数参数
Properties属性
Autowiring mode自动注入方式:no(默认值)、byName、byType、 constructor
Lazy initialization mode是否懒加载
Initialization method初始化方法
Destruction methodbean销毁后回调方法

表格中的内容我们可以从官网中找到,转变成xml配置如下所示:

<bean id="exampleBean" name="name1, name2, name3" class="com.javadoop.ExampleBean"
      scope="singleton" lazy-init="true" init-method="init" destroy-method="cleanup">

    <!-- 可以用下面三种形式指定构造参数 -->
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg index="0" value="7500000"/>

    <!-- property 的几种情况 -->
    <property name="beanOne">
        <ref bean="anotherExampleBean"/>
    </property>
    <property name="beanTwo" ref="yetAnotherBean"/>
    <property name="integerProperty" value="1"/>
</bean>

了解<bean/>标签中的属性后,我们再回过头去看是怎么转到BeanDefinitionHolder

// 404行
// org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement(org.w3c.dom.Element)
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
	return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
	// 获取id
	String id = ele.getAttribute(ID_ATTRIBUTE);
	// 获取name,有分割符号的
	String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

	List<String> aliases = new ArrayList<>();
	if (StringUtils.hasLength(nameAttr)) {
		// 用逗号,分号,空格分割name,作为别名放到aliases数组中
		String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
		aliases.addAll(Arrays.asList(nameArr));
	}
	// 默认将id设置为beanName
	String beanName = id;
	// 如果id为空,name不为空,则取第一个name作为beanName
	if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
		beanName = aliases.remove(0);
		if (logger.isTraceEnabled()) {
			logger.trace("No XML 'id' specified - using '" + beanName +
					"' as bean name and " + aliases + " as aliases");
		}
	}
	// 此处调用入参为null,跳过
	if (containingBean == null) {
		checkNameUniqueness(beanName, aliases, ele);
	}
	// 【重点】构造beanDefinition
	AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
	if (beanDefinition != null) {
		// 如果id和name都为空,那么beanName是null
		if (!StringUtils.hasText(beanName)) {
			try {
				// 此处入参为null,跳过
				if (containingBean != null) {
					beanName = BeanDefinitionReaderUtils.generateBeanName(
							beanDefinition, this.readerContext.getRegistry(), true);
				}
				else {
					// 如果不定义id和name,文章开头的例子中
					// beanName为com.muskmelon.domain.Person#0
					// beanNameClass为com.muskmelon.domain.Person
					beanName = this.readerContext.generateBeanName(beanDefinition);
					String beanClassName = beanDefinition.getBeanClassName();
					if (beanClassName != null &&
							beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
							!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
						// 把beanClassName设置为Bean别名	
						aliases.add(beanClassName);
					}
				}
				if (logger.isTraceEnabled()) {
					logger.trace("Neither XML 'id' nor 'name' specified - " +
							"using generated bean name [" + beanName + "]");
				}
			}
			catch (Exception ex) {
				error(ex.getMessage(), ele);
				return null;
			}
		}
		String[] aliasesArray = StringUtils.toStringArray(aliases);
		// 将BeanDefinition封装到BeanDefinitionHolder中
		return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
	}

	return null;
}

然后,我们看看是怎么根据配置创建BeanDefinition

// 500行
// org.springframework.beans.factory.xml.BeanDefinitionParserDelegate#parseBeanDefinitionElement()
public AbstractBeanDefinition parseBeanDefinitionElement(
			Element ele, String beanName, @Nullable BeanDefinition containingBean) {
	
	this.parseState.push(new BeanEntry(beanName));

	String className = null;
	if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
		className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
	}
	String parent = null;
	if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
		parent = ele.getAttribute(PARENT_ATTRIBUTE);
	}

	try {
		// 创建BeanDefinition,设置类信息
		AbstractBeanDefinition bd = createBeanDefinition(className, parent);
		// 设置BeanDefinition属性(懒加载,作用域,自动装配方式等等)
		parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
		bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
		// 下面是解析<bean/>标签下的子标签,然后注入到BeanDefinition中
		// 解析<meta/>
		parseMetaElements(ele, bd);
		// 解析<lookup-method/>
		parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
		// 解析<replaced-method/>
		parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
		// 解析<constructor-arg/>
		parseConstructorArgElements(ele, bd);
		// 解析<property/>
		parsePropertyElements(ele, bd);
		// 解析<qualifier/>
		parseQualifierElements(ele, bd);

		bd.setResource(this.readerContext.getResource());
		bd.setSource(extractSource(ele));

		return bd;
	}
	catch (ClassNotFoundException ex) {
		error("Bean class [" + className + "] not found", ele, ex);
	}
	catch (NoClassDefFoundError err) {
		error("Class that bean class [" + className + "] depends on not found", ele, err);
	}
	catch (Throwable ex) {
		error("Unexpected failure during bean definition parsing", ele, ex);
	}
	finally {
		this.parseState.pop();
	}

	return null;
}

以上就是<bean/>标签解析成BeanDefinition的全过程。继续看

BeanDefinition注册到容器

回过头我们看解析<bean/>标签的入口方法,看第一点上面已经描述完了,我们看第三点,将BeanDefinition注册到容器

// 305行
// org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader#processBeanDefinition
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
	// 1.将<bean/>标签中的信息提取出来,封装到BeanDefinitionHolder中
	BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
	if (bdHolder != null) {
		// 2. 如果有自定义属性的话,也进行相应解析,这里先忽略
		bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
		try {
			// 3. 将BeanDefinition注册到容器
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
		}
		catch (BeanDefinitionStoreException ex) {
			getReaderContext().error("Failed to register bean definition with name '" +
					bdHolder.getBeanName() + "'", ele, ex);
		}
		// 发送注册完事件
		getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
	}
}

入参的BeanDefinitionHolder中有beanNameBeanDefinition

// 158 行
// org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerBeanDefinition
public static void registerBeanDefinition(
			BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
			throws BeanDefinitionStoreException {

	// 获取beanName
	String beanName = definitionHolder.getBeanName();
	// 注册BeanDefinition
	registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

	// 注册别名,内部用map存储,key为beanName;用别名获取的时候,会将alias转换为beanName,然后再查找
	String[] aliases = definitionHolder.getAliases();
	if (aliases != null) {
		for (String alias : aliases) {
			registry.registerAlias(beanName, alias);
		}
	}
}
// 922行
// org.springframework.beans.factory.support.DefaultListableBeanFactory#registerBeanDefinition
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

	Assert.hasText(beanName, "Bean name must not be empty");
	Assert.notNull(beanDefinition, "BeanDefinition must not be null");
	// 
	if (beanDefinition instanceof AbstractBeanDefinition) {
		try {
			((AbstractBeanDefinition) beanDefinition).validate();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
					"Validation of bean definition failed", ex);
		}
	}
	// 获取已存在的bean
	BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
	// 处理beanName重复的场景
	if (existingDefinition != null) {
		// 判断是否支持bean覆盖,如果不支持,则抛出异常
		if (!isAllowBeanDefinitionOverriding()) {
			throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
		}
		else if (existingDefinition.getRole() < beanDefinition.getRole()) {
			// 框架定义的bean覆盖用户自定义的bean
			if (logger.isInfoEnabled()) {
				logger.info("Overriding user-defined bean definition for bean '" + beanName +
						"' with a framework-generated bean definition: replacing [" +
						existingDefinition + "] with [" + beanDefinition + "]");
			}
		}
		else if (!beanDefinition.equals(existingDefinition)) {
			// 用新的bean覆盖旧的bean
			if (logger.isDebugEnabled()) {
				logger.debug("Overriding bean definition for bean '" + beanName +
						"' with a different definition: replacing [" + existingDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		else {
			// 用相同的bean覆盖旧的bean,相同指equals返回true的bean
			if (logger.isTraceEnabled()) {
				logger.trace("Overriding bean definition for bean '" + beanName +
						"' with an equivalent definition: replacing [" + existingDefinition +
						"] with [" + beanDefinition + "]");
			}
		}
		// 将新的beanDefinition放入map中
		this.beanDefinitionMap.put(beanName, beanDefinition);
	}
	else {
		// 判断bean是否开始初始化
		if (hasBeanCreationStarted()) {
			// 加锁,bean初始化阶段,map不可被修改
			synchronized (this.beanDefinitionMap) {
				this.beanDefinitionMap.put(beanName, beanDefinition);
				List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
				updatedDefinitions.addAll(this.beanDefinitionNames);
				updatedDefinitions.add(beanName);
				this.beanDefinitionNames = updatedDefinitions;
				removeManualSingletonName(beanName);
			}
		}
		else {
			// 将BeanDefinition放到map中
			this.beanDefinitionMap.put(beanName, beanDefinition);
			// 记录beanName,放到ArrayList数组中
			this.beanDefinitionNames.add(beanName);
			// 移除手动注册的bean
			removeManualSingletonName(beanName);
		}
		this.frozenBeanDefinitionNames = null;
	}

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

从上面代码中我们看到,将BeanDefinition注册到容器中,其实就是将beanNameBeanDefinition以key-value的形式存储到beanDefinitionMap中。
到这里,我们已经比较清楚的知道xml配置文件中,一个<bean/> 标签是如何被解析并注册到容器中了。
注意:到这里bean还未进行实例化,我们只是将Bean的定义注册到容器中。

那究竟Bean什么时候实例化呢,我们来看refresh方法里调用的finishBeanFactoryInitialization

【重点】finishBeanFactoryInitialization

初始化所有的单例bean,且非懒加载的

// 851 行
// org.springframework.context.support.AbstractApplicationContext#finishBeanFactoryInitialization
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}

	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}

	// 先初始化LoadTimeWeaverAware 类型的 bean
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

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

	// 冻结bean解析,加载,注册操作
	beanFactory.freezeConfiguration();

	// 开始实例化
	beanFactory.preInstantiateSingletons();
}
// 860 行
// org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
public void preInstantiateSingletons() throws BeansException {
	if (logger.isTraceEnabled()) {
		logger.trace("Pre-instantiating singletons in " + this);
	}

	// 
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// 遍历bean
	for (String beanName : beanNames) {
		// 获取父类beanDefinition,没有父类返回当前类的beanDefinition
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 不是抽象,是单例,不是懒加载 允许初始化
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			// 校验是否为FactoryBean,beanName前加上&符号,再调用getBean
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					final 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(beanName);
			}
		}
	}

	// Trigger post-initialization callback for all applicable beans...
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			}
			else {
				smartSingleton.afterSingletonsInstantiated();
			}
		}
	}
}

接下去就是getBean方法的解析了,本篇重点讲述Spring Ioc容器初始化的过程,getBean 我们后面章节描述Bean生命周期的时候重点描述

总结

IOC容器初始化关键步骤

  • 读取配置文件,解析成BeanDefinition
  • 注册BeanDefinition到容器,容器内部使用ConcurrentHashMap存储Bean定义,其中beanName为key,BeanDefinition为value
  • 对单例Bean进行实例化

除了初始化之外IOC相关还有很多其他的知识点,例如:Bean的生命周期是怎么样的,如何解决循环依赖问题,父子容器有什么关系等等。小编将在后续的文章中呈现给大家,敬请期待~

参考资料

  1. Spring IOC 容器源码分析
  2. Spring Framework官方文档
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值