Spring源码简读之Bean对象的“前世今生”
前言
本文旨在梳理Spring源码中IOC容器的创建以及Bean对象的创建流程和整理脉络,通过阅读源代码,了解Bean对象的“前世今生”,其中不过多赘述其中某些方法的具体实现,如感兴趣,可自行调试并阅读。
一、Spring容器和Bean对象的创建流程
Spring最重要的核心组件就是IOC,IOC的思想就是通过容器来管理Bean对象,IOC容器就像是一个生产产品的流水线上的机器,Spring创建出来的Bean就好像是流水线的终点生产出来的一个个精美绝伦的产品。通过对Spring源码的阅读,我将整个IOC容器的创建和Bean的加载过程可以通过下面的图来简单梳理。
为了便于大家理解,现将图中的几个核心组件进行介绍
1.1核心组件
1.1.1 配置元信息
Spring IOC容器将对象实例的创建与对象实例的使用分离,当业务中需要依赖某个对象,不再依靠我们自己手动创建,只需向Spring要,Spring就会以注入的方式交给我们需要的依赖对象。既然将对象创建的任务交给了Spring,那么Spring就需要知道创建一个对象所需要的一些必要的信息。而这些必要的信息可以是Spring过去支持最完善的xml配置文件,或者是其他形式的例如properties的磁盘文件,也可以是现在主流的注解,甚至是直接的代码硬编码。总之,这些创建对象所需要的必要信息称为配置元信息。
1.2.1 BeanDefination
那么Spring是如何将这些配置文件中的配置元信息加载到内存中,来创建Bean对象的呢?BeanDefinition 是定义 Bean 的配置元信息接口,简单说就是对Bean信息的定义。描述一个bean的全部信息,比如他的class类型、Bean的作用域、是否懒加载等,Spring中每一个被扫描到的bean都会生成一个BeanDefinition,即配置元信息被加载到内存之后是以BeanDefination的形存在的即可。
1.3.1 BeanDefinationReader
Spring是如何看懂这些配置元信息的呢?这个就要靠我们的BeanDefinationReader了。不同的BeanDefinationReader拥有不同的功能,如果我们要读取xml配置元信息,那么可以使用XmlBeanDefinationReader。如果我们要读取properties配置文件,那么可以使用PropertiesBeanDefinitionReader加载。而如果我们要读取注解配置元信息,那么可以使用 AnnotatedBeanDefinitionReader加载。我们也可以很方便的自定义BeanDefinationReader来自己控制配置元信息的加载。总的来说,BeanDefinationReader的作用就是加载配置元信息,并将其转化为内存形式的BeanDefination。
1.4.1 BeanDefinationRegistory
Spring将存在于各处的配置元信息加载到内存,并转化为BeanDefination的形式后。当我们需要创建某一个对象实例的时候,找到相应的BeanDefination然后创建对象即可。那么我们需要某一个对象的时候,去哪里找到对应的BeanDefination呢?这种通过Bean定义的id找到对象的BeanDefination的对应关系或者说映射关系又是如何保存的呢?这就引出了BeanDefinationRegistry了。
Spring通过BeanDefinationReader将配置元信息加载到内存生成相应的BeanDefination之后,就将其注册到BeanDefinationRegistry中,BeanDefinationRegistry就是一个存放BeanDefination的大篮子,它也是一种键值对的形式,通过特定的Bean定义的id,映射到相应的BeanDefination。
1.5.1 BeanFactoryPostProcesser
BeanFactoryPostProcessor是容器启动阶段Spring提供的一个扩展点,主要负责对注册到BeanDefinationRegistry中的一个个的BeanDefination进行一定程度上的修改与替换。例如我们的配置元信息中有些可能会修改的配置信息散落到各处,不够灵活,修改相应配置的时候比较麻烦,这时我们可以使用占位符的方式来配置。
1.6.1 BeanFactory
既然是以Factory结尾,表示它是一个工厂类(接口), 它负责生产和管理bean的一个工厂。在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory只是个接口,并不是IOC容器的具体实现,但是Spring容器给出了很多种实现,如 DefaultListableBeanFactory、XmlBeanFactory、ApplicationContext等,其中XmlBeanFactory就是常用的一个,该实现将以XML方式描述组成应用的对象及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
1.7.1 各种Aware接口
aware翻译的中文意思是意识到的,察觉到的。在Spring中有很多Aware接口,例如BeanNameAware,ApplicationContextAware等,它们的的作用有一个共同的目的就是,在Bean初始化的过程中来获取Spring的各种资源。当然,我们在对Spring进行扩展的时候也可以自定义Aware接口来实现Bean初始化的过程中对利用Spring容器的资源对Bean进行一些处理。
1.8.1 BeanPostProcesser
BeanPostProcesser接口也叫后置处理器,作用是在Bean对象在初始化的过程中,在显示调用初始化方法的前后添加我们自己的逻辑。我们在项目开发中可能经常会遇到对Bean对象初始化之前和之后做一些准备工作和收尾工作,常用的例如@PostContruct注解,就是在Bean初始化之前做一些处理,也就是通过后置处理器来进行操作的。
1.2 核心代码概览
相信看过Spring源码的朋友们对下面的方法肯定不会陌生,refresh方法是AbstractApplicationContext中的方法,也是IOC容器的最核心方法,通过它可以了解容器的创建和Bean加载的过程,大家可以通过代码中的注释,对流程有个大体的了解,感兴趣的话可以仔细阅读其中的每一个方法。这里只介绍每个方法的主要作用。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 准备刷新的上下文环境.
// 刷新上下文环境,初始化上下文环境,对系统的环境便利或者系统属性进行准备和校验
prepareRefresh();
// 通知子类准备刷新的Bean工厂
//获取新的beanFactory,销毁原有beanFactory、为每个bean生成BeanDefinition等
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备上下文中的Bean工厂
// 对bean工厂的工作功能进行填充,配置工厂的标准上下文特征,例如上下文的ClassLoader和后处理器。
prepareBeanFactory(beanFactory);
try {
//允许在上下文子类中对 bean 工厂进行后置处理。在beanfactory加载完成所有的bean后,想修改其中某个bean的定义,
//或者对beanFactory做一些其他的配置,就可以在子类中对beanFactory进行后置处理(子类通过实现接口
//BeanFactoryPostProcessor来自定义后置处理)。后置处理器执行的时间是:在所有的beanDenifition加载完成
//之后,bean实例化之前执行。
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 触发上下文中的bean工厂的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册bean的后置处理器,对bean的创建进行拦截,并进行相应的处理
// 实例化和注册beanFactory中扩展了BeanPostProcessor的bean。例如
// AutowiredAnnotationBeanPostProcessor(处理被@Autowired注解修饰的bean并注入)
// CommonAnnotationBeanPostProcessor(处理@PreDestroy、@PostConstruct、@Resource等多个注解的作用)等。
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// 初始化国际化工具类MessageSource。
initMessageSource();
// 初始化应用事件广播器。
initApplicationEventMulticaster();
// 这个方法在AbstractApplicationContext中没有实现,留给子类来初始化其他的Bean,
//是个模板方法,在容器刷新的时候可以自定义逻辑(子类自己去实现逻辑),不同的Spring容器做不同的事情
onRefresh();
// 注册监听器,并且广播earlyApplicationEvents,也就是早期的事件
registerListeners();
// 初始化完剩下的单例(非懒加载的单例类)并调用BeanPostProcessors。
//剩下的(非懒加载)单例Bean也就是我们自己定义的那些Bean,比如invokeBeanFactoryPostProcessors
//方法中根据各种注解解析出来的类(扫描的@Bean之类的),在这个时候都会被初始化,
//扫描的@Bean之类的,实例化的过程各种BeanPostProcessor开始起作用。
finishBeanFactoryInitialization(beanFactory);
// 通知生命周期处理器LifecycleProcessor完成刷新过程,同时发出ContextRefreshEvent通知别人
finishRefresh();
}
}
}
二、Bean对象加载的具体流程
经过第一章节的概括,相信大家对Spring的IOC容器和Bean对象的有了大致的了解,对Bean对象的生命周期有了进一步的了解,下面我将Spring的Bean对象的加载过程简单分为两个阶段,分别为解析注册BeanDefination阶段和Bean对象的创建阶段,本章以XML配置文件为例来详细介绍Bean的加载过程。
2.1 解析并注册BeanDefination
2.1.1 加载XML文件到XmlBeanFactory
首先,看一下XmlBeanFactory 的代码,如下:
public class XmlBeanFactory extends DefaultListableBeanFactory {
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
/**
* Create a new XmlBeanFactory with the given resource,
* which must be parsable using DOM.
* @param resource the XML resource to load bean definitions from
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, null);
}
/**
* Create a new XmlBeanFactory with the given input stream,
* which must be parsable using DOM.
* @param resource the XML resource to load bean definitions from
* @param parentBeanFactory parent bean factory
* @throws BeansException in case of loading or parsing errors
*/
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}
}
其XmlBeanFactory继承了DefaultListableBeanFactory,而DefaultListableBeanFactory为整个Bean加载的核心部分,是Spring注册及加载bean的默认实现,而不同的是XmlBeanFactory使用的自定义的XmlBeanDefinitionReader来读取BeanDefinition,其中参数Resource接口抽象了所有Spring内部使用到的底层资源:File,URL,Classpath等。
2.1.2 解析并注册BeanDefinition
XmlBeanFactory中最重要的方法就是this.reader.loadBeanDefinitions(resource),即加载BeanDefinition,我们跟进代码就可以找到里面最重要的方法,如下图
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//将资源文件解析为Document
Document doc = doLoadDocument(inputSource, resource);
//解析及注册BeanDefinations
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
其中,doLoadDocument(inputSource, resource);和registerBeanDefinitions(doc, resource)分别获取Document对象和解析并注册BeanDefinitions。解析和注册bean的过程中首先会调用doRegisterBeanDefinitions,这其中用到了模版方法的设计模式,preProcessXml和postProcessXml为模版方法的扩展接口,解析BeanDefiniton的工作都在parseBeanDefinitions方法中。
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//模版方法
preProcessXml(root);
//解析BeanDefinition
parseBeanDefinitions(root, this.delegate);
//模版方法
postProcessXml(root);
this.delegate = parent;
}
进入到parseBeanDefinition方法中,可以看到就是简单的对Document元素进行了解析,通过委派给BeanDefinitionParserDelegate来进行元素的解析,可以在BeanDefinitionParserDelegate中看到Bean的属性。
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)) {
//注册BeanDefinition
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
public class BeanDefinitionParserDelegate {
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";
/**
* Value of a T/F attribute that represents true.
* Anything else represents false.
*/
public static final String TRUE_VALUE = "true";
public static final String FALSE_VALUE = "false";
public static final String DEFAULT_VALUE = "default";
public static final String DESCRIPTION_ELEMENT = "description";
public static final String AUTOWIRE_NO_VALUE = "no";
public static final String AUTOWIRE_BY_NAME_VALUE = "byName";
public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";
public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";
public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";
public static final String NAME_ATTRIBUTE = "name";
public static final String BEAN_ELEMENT = "bean";
public static final String META_ELEMENT = "meta";
public static final String ID_ATTRIBUTE = "id";
public static final String PARENT_ATTRIBUTE = "parent";
public static final String CLASS_ATTRIBUTE = "class";
public static final String ABSTRACT_ATTRIBUTE = "abstract";
public static final String SCOPE_ATTRIBUTE = "scope";
private static final String SINGLETON_ATTRIBUTE = "singleton";
public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";
public static final String AUTOWIRE_ATTRIBUTE = "autowire";
public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";
public static final String PRIMARY_ATTRIBUTE = "primary";
public static final String DEPENDS_ON_ATTRIBUTE = "depends-on";
public static final String INIT_METHOD_ATTRIBUTE = "init-method";
public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";
public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method";
}
至此,BeanDefinition已经从Document对象解析完毕,接下来就是以beanName为key注册到map里,我们继续看代码,上面提到的parseBeanDefinitions方法中最重要的方法为parseDefaultElement(ele, delegate),而它其中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry())方法则是真正注册BeanDefinition的最终实现。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//通过bean标签来获取注册bean
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
最终,会统一注册到最开始提到的Spring核心容器DefaultListableBeanFactory中的private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
里。至此,BeanDefinition完成了解析和注册。
2.2 Bean对象的创建
容器启动后,BeanDefination已经解析并注册到Spring核心容器DefaultListableBeanFactory中,接下来就应该获取Bean对象,完成Bean对象的加载。因此,我们可以看一下getBean方法。DefaultListableBeanFactory继承DefaultListableBeanFactory类,然后DefaultListableBeanFactory类继承AbstractBeanFactory类,AbstractBeanFactory类中的getBean方法则是获取bean对象的核心方法。
同样,我也可以在第一章介绍的refresh方法中的finishBeanFactoryInitialization(beanFactory);中找到对getBean方法的调用,意味着在完成BeanFactory初始化的最后,会将Bean对象注入到BeanFactory中,完成Bean对象的加载。具体方法跟进如下:
上面方法中可以清楚的看到,从BeanDefination到Bean的转化,感兴趣的朋友们可以跟进代码详细查看。上图的getBean方法即是AbstractBeanFactory的getBean方法,而其中的doGetBean()方法的总体功能就是在创建bean对象之前,先去缓存或者beanFactory工厂中查看是否存在bean,如果存在,则返回,不存在,则进行对应的创建流程。下面我们详细分析一下doGetBean()方法,感兴趣的可以仔细阅读注释。
public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
throws BeansException {
return doGetBean(name, requiredType, args, false);
}
@SuppressWarnings("unchecked")
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
//提取对应的beanName
String beanName = transformedBeanName(name);
Object beanInstance;
// 检查缓存中或者实例工厂中是否有对应的实例
//为什么会使用这段代码呢?
//因为在创建单里bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖
//Spring创建bean的原则是不等bean创建完成就会将bean的ObjectFactory提早曝光
//也就是将ObjectFactory加入到缓存中,一旦下一个bean创建的时候需要依赖上个bean则直接使用ObjectFactory
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
//返回对应的实例
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 只有在单例模式下才会尝试解决循环依赖
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 查看beanDefination是否存在
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// 如果beanDefinationMap中不存在,则尝试从parentBeanFactory中检测
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
//将存储在xml配置文件的GernericBeanDefinition转换成RootBeanDefinition
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
String[] dependsOn = mbd.getDependsOn();
//若存在依赖则需要递归实例化依赖的bean
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
//缓存依赖调用
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// 创建bean实例
if (mbd.isSingleton()) {
//重要的事情说三遍
//获取单例Bean对象
//获取单例Bean对象
//获取单例Bean对象
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// 原型模式bean创建
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
if (!StringUtils.hasLength(scopeName)) {
throw new IllegalStateException("No scope name defined for bean ´" + beanName + "'");
}
Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex);
}
}
}
catch (BeansException ex) {
beanCreation.tag("exception", ex.getClass().toString());
beanCreation.tag("message", String.valueOf(ex.getMessage()));
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
finally {
beanCreation.end();
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
至此,Bean对象的加载已经基本完成,在使用的时候可以通过getBean方法来获取IOC容器中的Bean对象,那么可能有人会疑问,那Bean对象加载完之后,到底存储在哪里呢?起初在我没看到源码之前,我的思路在Bean对象加载完成之后,即Bean对象初始化后可能会将Bean对象存储到某种缓存里,参考BeanDefination的思想,我猜Bean对象同样应该存储到ConcurrenHashMap里。而且该动作应该就是doCreateBean里,初始化完成之后,将Bean对象添加到ConcurrenHashMap里。带着我的猜想,我跟进了上图中的 getSingleton方法,方法顾名思义获取单例Bean对象,而真正的目的是从缓存中获取单例bean,通过回调函数也可以看到,createBean方法是创建Bean对象的意思,因此进入getSingleton如下:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 从缓存池中获取bean:singletonObjects 一级缓
Object singletonObject = this.singletonObjects.get(beanName);
// 如果一级缓存中为null
if (singletonObject == null) {
//初始化前操作,校验是否 beanName 是否有别的线程在初始化,并记录beanName的初始化状态
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 调用createBean方法实例化bean
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
//初始化后的操作,移除初始化状态
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName);
}
if (newSingleton) {
//重要的事情说三遍
// 注册单例Bean到缓存
// 注册单例Bean到缓存
// 注册单例Bean到缓存
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
该方法返回在给定名称下注册的(原始)单例对象,如果还没有注册,则通过回调函数createBean创建并注册一个新的单例对象。具体的执行步骤如下:
(1)检查缓存是否已经加载过
(2)没有加载,则记录beanName 的加载状态
(3)调用createBean()方法实例化 bean
(4)bean实例化完成之后,移除初始化状态
(5)将实例化结果记录到缓存并删除加载 bean 过程中所记录到的各种辅助状态
那么创建Bean对象和注册Bean对象的操作都在这个方法里,仔细阅读源码,发现addSingleton(beanName, singletonObject)就是我们要找的方法,请看下面代码:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 将Bean对象存储到singletonObjects集合中
this.singletonObjects.put(beanName, singletonObject);
// 移除工厂方法
this.singletonFactories.remove(beanName);
// 从早期单例对象集合中移除
this.earlySingletonObjects.remove(beanName);
// 注册单例对象名称
this.registeredSingletons.add(beanName);
}
}
上面的代码,非常简单易懂,singletonObjects就是我前面猜想的ConcurrentHashMap集合,用来缓存单例Bean对象的。earlySingletonObjects 变量,它也是单例缓存,也是用来保存 beanName 和 创建 bean 实例之间的关系。与 singletonFactories 不同的是,当一个单例 bean 被放入到这 early 单例缓存后,就要从 singletonFactories 中移除,两者是互斥的,主要用来解决循环依赖的问题。
当Bean的作用域为单例时,第一次初始化后的Bean对象会被存储到singletonObjects里,再次使用的时候直接从缓存里获取即可。最后,我们再看看当缓存中没有Bean对象时,Bean对象是如何创建的,请看createBean方法。
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
if (logger.isTraceEnabled()) {
logger.trace("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
// 确保此时bean类已经被解析,并且克隆 bean 定义,以防动态解析的类不能存储在共享合并 bean 定义中。
// 锁定 class,根据设置的 class 属性或者根据 className 来解析 Class
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// 验证及准备重写的方法
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// 解析指定bean,让 beanPostProcessor 有机会返回代理而不是目标bean实例。
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
// 短路操作,如果代理成功创建 bean 后,直接返回
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
try {
//重要的事情说三遍
//创建Bean对象
//创建Bean对象
//创建Bean对象
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isTraceEnabled()) {
logger.trace("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
}
}
上面这段代码的执行流程如下:
(1)根据设置的 class 属性或者根据 className 来解析 Class
(2)验证及准备覆盖的方法 这个方法是用来处理以下两个配置的:我们在解析默认标签时,会识别 lookup-method 和 replaced-method 属性,然后这两个配置的加载将会统一存放在 beanDefinition 中的 methodOverrides 属性里。
(3)应用初始化前的后处理器,解析指定 bean 是否存在初始化前的短路操作
(4)创建 bean
正如上段代码所示,createBean方法中的doCreateBean方法应该是真正创建Bean对象的方法,我们话不多说,继续跟进,一探究竟。
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 实例化Bean
BeanWrapper instanceWrapper = null;
// 如果bean是单例,就先清除缓存中的bean信息
if (mbd.isSingleton()) {
// 根据指定bean使用对应的策略实例化bean,例如:工厂方法,构造函数自动注入,简单初始化
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 允许后置处理器修改合并的BeanDefinition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
//快速缓存单例以解析循环引用
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isTraceEnabled()) {
logger.trace("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
//第二个参数是回调接口,实现的功能是将切面动态织入 bean
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 初始化bean
Object exposedObject = bean;
try {
// 对 bean 进行填充,将各个属性值注入
// 如果存在对其它 bean 的依赖,将会递归初始化依赖的 bean
populateBean(beanName, mbd, instanceWrapper);
// 调用初始化方法,例如 init-method
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
// 循环依赖检查
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
// earlySingletonReference 只有在检测到有循环依赖的情况下才 不为空
if (earlySingletonReference != null) {
if (exposedObject == bean) {
// 如果 exposedObject 没有在初始化方法中被改变,也就是没有被增强
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// bean 创建后,它所依赖的 bean 一定是已经创建了
// 在上面已经找到它有依赖的 bean,如果 actualDependentBeans 不为空
// 表示还有依赖的 bean 没有初始化完成,也就是存在循环依赖
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
// 注册销毁bean对象
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
通过注释可以简单的看到上面的方法中完成了bean的创建、初始化和最后的销毁,加载bean对象最终的操作就在此方法完成。
最后,通过上面对源码的跟踪和简单讲解,我们基本上了解了Bean对象的创建过程。
三、总结
本文第一章通过介绍refresh方法,简单讲解了整个IOC容器的创建过程,而第二章则是真正的通过讲解源代码介绍了Bean对象的加载过程,即如何从xml文件变成了Bean对象,并注入到了IOC容器中,至此,Spring中最核心的组件IOC容器和它所管理的Bean对象就介绍到这里。