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-beans
,spring-core
,spring-aop
,spring-express
,spring-jcl
这几个核心的包
代码很好理解,我们通过ClassPathXmlApplicationContext
类来启动容器。读取xml配置,根据xml配置文件内容创建ApplicationContext
。我们先看一下ClassPathXmlApplicationContext
的继承结构
我们可以看到ClassPathXmlApplicationContext
经过多个好几个抽象类才到ApplicationContext
,除了ClassPathXmlApplicationContext
之外,还有FileSystemXmlApplicationContext
,AnnotationConfigApplicationContext
能创建容器
ClassPathXmlApplicationContext
:从classpath读取配置文件FileSystemXmlApplicationContext
:从系统路径读取配置文件AnnotationConfigApplicationContext
:基于注解使用,采用java配置类和各种注解来配置,熟悉的朋友应该知道@Configuration
本文为了方便理解整个容器构建流程,所以使用ClassPathXmlApplicationContex
t进行分析
文章开头的例子中,第一行代码就是用来创建容器的,我们一起来深入研究一下容器的启动过程。在介绍容器启动过程之前,我们先来了解一下两个比较关键的术语:BeanFactory
和BeanDefinition
BeanFactory
BeanFactory,从字面意思上理解为生产Bean的工厂,负责生产和管理Bean实例。
也许有人会有疑问,这个BeanFactory
也是容器吗,和前面的ApplicationContext
有什么关系?源码注释中有这么一句话:
The root interface for accessing a Spring bean container
表示BeanFactory是Spring容器最顶层的接口,再看一下继承结构
BeanFactory主要有三个实现接口ListableBeanFactory
,HierarchicalBeanFactory
,AutowireCapableBeanFactory
,主要用途分别如下:
ListableBeanFactory
:提供了获取多个Bean的方法,从源码中能看到,BeanFactory
只提供了获取单个Bean的方法HierarchicalBeanFactory
:父子级联 IoC 容器的接口,子容器可以通过接口方法访问父容器; 通过 HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean,但父容器不能访问子容器的 BeanAutowireCapableBeanFactory
:定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法
上面的ApplicationContext
实现了ListableBeanFactory
,HierarchicalBeanFactory
两个接口,并没有实现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();
}
了解主要的两个术语BeanFactory
和BeanDefinition
之后,接下来我们去看看容器启动的过程究竟是发生了什么
容器启动步骤
我们先从宏观的角度看一下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提供了两种命名空间节点解析的方式parseDefaultElement
与parseCustomElement
,有什么区别呢,往下看
// 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个:import
,alias
,bean
,beans
主要看一下对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 method | bean销毁后回调方法 |
表格中的内容我们可以从官网中找到,转变成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
中有beanName
和BeanDefinition
// 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
注册到容器中,其实就是将beanName
和BeanDefinition
以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的生命周期是怎么样的,如何解决循环依赖问题,父子容器有什么关系等等。小编将在后续的文章中呈现给大家,敬请期待~