测试用例
依然使用这个官网上的用例,来进行调试;

Person.java

package org.shangyang.spring.container;/**- - @author shangyang**/public class Person {String name;Person spouse;public String getName() {return name;}public void setName(String name) {this.name = name;}public Person getSpouse() {return spouse;}public void setSpouse(Person spouse) {this.spouse = spouse;}}

beans.xml

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 传统的方式 --><bean name="john" class="org.shangyang.spring.container.Person"><property name="name" value="John Doe"/><property name="spouse" ref="jane"/></bean><bean name="jane" class="org.shangyang.spring.container.Person"><property name="name" value="Jane Doe"/></bean>
</beans>
@Test
public void testApplicationContext(){@SuppressWarnings("resource")ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");Person p = context.getBean("john", Person.class);assertEquals("John Doe", p.getName() );assertEquals("Jane Doe", p.getSpouse().getName() );}

源码分析
备注,这里只针对 Spring 容器实例化 singleton bean 的主流程进行介绍;singleton bean 在 Spring 容器中被初始化的特点是,在 Spring 容器的启动过程中就进行初始化;

(最好的分析源码的方式,就是通过高屋建瓴,逐个击破的方式;首先通过流程图获得它的蓝图(顶层设计图),然后再根据蓝图上的点逐个击破;最后才能达到融会贯通,胸有成竹的境界;所以,这里作者用这样的方式带你深入剖析 Spring 容器里面的核心点,以及相关主流程到底是如何运作的。)

主流程

本章节我们将详细去阐述的是,Spring 容器是如何对 Singleton bean 进行初始化并注册到当前容器的;与之相关的主要有两个流程,

解析 bean definitions 并注册
解析 bean definitiions 并注册到当前的 BeanFactory 中;此步骤是在 step 1.1.1.2 obtainFreshBeanFactory 完成;更详细的介绍参考解析并注册 bean definitions 流程

从 #1 中找到所有的已注册的 singleton bean definitions,遍历,实例化得到 Singleton beans;此步骤对应的是 step 1.1.1.11 finishBeanFactoryInitialization 开始进行 singleton bean 的构造过程,其后调用AbstractBeanFactory#getBean(beanFactory)方法进行构造;更详细的介绍参考 Do Get Bean 流程。
解析并注册 bean definitions 流程
Do Get Bean 流程
Do Get Bean 流程的入口是 AbstractBeanFactory#doGetBean 方法,主流程图如下,

主流程大致为,从缓存中找到是否已经实例化了该 singleton bean,如果已经实例化好了,那么就直接返回;如果在缓存中没有找到,则将当前的 bean 封装为 RootBeanDefinition,然后通过调用 DefaultSingletonBeanRegistry#getSingleton 得到初始化好的 singleton bean,然后将其注册至缓存( step 1.3.3 addSingleton ),然后再判断是普通 bean 还是 factory bean 作必要的处理( step 1.4 getObjectForBeanInstance )后,最后返回;

RootBeanDefinition
初始化了一个 RootBeanDefinition 对象,正如其类名描述的那样,是该 bean 的顶层描述;包含了 bean 的字段属性,ref属性以及继承相关等等属性;

Step 1.3:DefaultSingletonBeanRegistry#getSingleton
此步骤的相关代码如下,

// Create bean instance.
if (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {@Overridepublic Object getObject() throws BeansException {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}}});bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}

调用父类 DefaultSingletonBeanRegistry#getSingleton 方法;注意,这里通过接口 ObjectFactory<Object> 定义了一个回调方法 getObject(),通过该回调方法调用 AbstractAutowireCapableBeanFactory#createBean 方法,通过此回调方法正式拉开了实例化 bean 的序幕。

Step 1.3.1.1:AbstractAutowireCapableBeanFactory#createBean
AbstractAutowireCapableBeanFactory#doCreateBean 方法是初始化 bean 的最核心的入口方法,执行流程如 Do Get Bean 流程所示,

主流程主要做了这么三件事情,一、instantiate bean;二、populate bean;三、initialize bean;

包含五个子流程,他们分别是 factory instantiate bean、autwire instantiate bean、default instantiate bean、populate bean 以及 initialize bean,其中,前三个子流程对应第一件事情,实例化 bean;其次的子流程 populate bean 对应的是第二件事情,为 bean 设置 property 参数;最后一个子流程 [initialize bean] 对应最后一件事情既初始化 bean,这里的初始化指的是是对创建好的 bean 做一些修饰动作的。
下面我们分别来分析这三件事情

第一件事情:instantiate bean
该步骤对应 Do Get Bean 流程中的 Step 1.3.1.1.3.1 createBeanInstance;根据 bean 的不同配置方式,实现了三种实例化 bean 的方式,分别是 factory instantiate bean、autwire instantiate bean 以及 default instantiate bean;

factory instantiate bean
用工厂方法实例化 bean,待叙;

autwire instantiate bean
通过 autowire 注解的方式实例化 bean,待叙;

default instantiate bean
此步骤对应 Do Get Bean 流程中的 Step 1.3.1.1.3.1.3 instantiateBean,其对应子流程 default instantiate bean 如下图所示,

注意几点

这里仅仅是通过使用其构造函数 constructor 使用Java 反射实例化了 bean,并没有对其进行任何的参数赋值,赋值过程参考 populate bean 流程;
将 bean 封装为 BeanWrapper,然后
注册 default PropertyEditor
注册 custom PropertyEditor
最后返回 BeanWrapper

第二件事情:populate bean
对应 Do Get Bean 流程中的 Step 1.3.1.1.3.4 populateBean,通过调用 AbstractAutowireCapableBeanFactory#populateBean 正式给 bean 的参数进行赋值;为什么方法名取名为populate呢?查百度翻译,结果是居住于、生活于、移民于、落户于的意思,丝毫没有赋值的意思,但是记得以前和美国人共事的时候,他们非常喜欢用这个词populate,特别是在创建某个对象的时候,他们特别喜欢用这个词;后来无意中发现,populate有创建和填充的意思,所以,这里的意思就是,填充这个 bean;下面看看 populate bean 的流程图,看看它是怎么玩的,

通过调用 AbstractAutowireCapableBeanFactory#applyPropertyValues 方法正式给 bean 进行赋值操作,赋值的主流程主要包括两个部分,resolve property value object 和 set property value to bean

resolve property value
对应上面 Sequence Diagram 中的 Step 1.5 - Step 1.7;这一步主要是去遍历当前 bean 所有的 property,并依次解析(resolve)得到对应的 Java 对象;通过方法 BeanDefinitionValueResolver#resolveValueIfNecessary 进行解析,解析的过程是针对不同类型的 Property,采用不同的解析方式,里面目前总共对应了十种类型,先看看它的源码,

public Object resolveValueIfNecessary(Object argName, Object value) {// We must check each value to see whether it requires a runtime reference// to another bean to be resolved.if (value instanceof RuntimeBeanReference) { // 这里表示该 bean definition ref 引用的是一个 bean,那么这里,必须对该 bean 进行初始化操作;RuntimeBeanReference ref = (RuntimeBeanReference) value;return resolveReference(argName, ref);}else if (value instanceof RuntimeBeanNameReference) {String refName = ((RuntimeBeanNameReference) value).getBeanName();refName = String.valueOf(doEvaluate(refName));if (!this.beanFactory.containsBean(refName)) {throw new BeanDefinitionStoreException("Invalid bean name '" + refName + "' in bean reference for " + argName);}return refName;}else if (value instanceof BeanDefinitionHolder) {// Resolve BeanDefinitionHolder: contains BeanDefinition with name and aliases.BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());}else if (value instanceof BeanDefinition) {// Resolve plain BeanDefinition, without contained name: use dummy name.BeanDefinition bd = (BeanDefinition) value;String innerBeanName = "(inner bean)" + BeanFactoryUtils.GENERATED_BEAN_NAME_SEPARATOR +ObjectUtils.getIdentityHexString(bd);return resolveInnerBean(argName, innerBeanName, bd);}else if (value instanceof ManagedArray) {// May need to resolve contained runtime references.ManagedArray array = (ManagedArray) value;Class<?> elementType = array.resolvedElementType;if (elementType == null) {String elementTypeName = array.getElementTypeName();if (StringUtils.hasText(elementTypeName)) {try {elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());array.resolvedElementType = elementType;}catch (Throwable ex) {// Improve the message by showing the context.throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,"Error resolving array type for " + argName, ex);}}else {elementType = Object.class;}}return resolveManagedArray(argName, (List<?>) value, elementType);}else if (value instanceof ManagedList) {// May need to resolve contained runtime references.return resolveManagedList(argName, (List<?>) value);}else if (value instanceof ManagedSet) {// May need to resolve contained runtime references.return resolveManagedSet(argName, (Set<?>) value);}else if (value instanceof ManagedMap) {// May need to resolve contained runtime references.return resolveManagedMap(argName, (Map<?, ?>) value);}else if (value instanceof ManagedProperties) {Properties original = (Properties) value;Properties copy = new Properties();for (Map.Entry<Object, Object> propEntry : original.entrySet()) {Object propKey = propEntry.getKey();Object propValue = propEntry.getValue();if (propKey instanceof TypedStringValue) {propKey = evaluate((TypedStringValue) propKey);}if (propValue instanceof TypedStringValue) {propValue = evaluate((TypedStringValue) propValue);}copy.put(propKey, propValue);}return copy;}else if (value instanceof TypedStringValue) {// Convert value to target type here.TypedStringValue typedStringValue = (TypedStringValue) value;Object valueObject = evaluate(typedStringValue);try {Class<?> resolvedTargetType = resolveTargetType(typedStringValue);if (resolvedTargetType != null) {return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);}else {return valueObject;}}catch (Throwable ex) {// Improve the message by showing the context.throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,"Error converting typed String value for " + argName, ex);}}else {return evaluate(value);}
}

这里主要关注两类解析,

RuntimeBeanReference 类型解析
对应需要被解析的配置为john的 property spouse,它所对应的值是另一个 bean jane;既是一个去解析一个ref bean。

<property name="spouse" ref="jane"/>

所以可以看到,源码中是通过 resolveReference 方法调用 AbstractBeanFactory#getBean 方法去实例化一个 bean jane 并返回;对应的源码如下,
BeanDefinitionValueResolver#resolveReference

/*** Resolve a reference to another bean in the factory.*/
private Object resolveReference(Object argName, RuntimeBeanReference ref) {try {String refName = ref.getBeanName();refName = String.valueOf(doEvaluate(refName));if (ref.isToParent()) {if (this.beanFactory.getParentBeanFactory() == null) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,"Can't resolve reference to bean '" + refName +"' in parent factory: no parent factory available");}return this.beanFactory.getParentBeanFactory().getBean(refName);}else {Object bean = this.beanFactory.getBean(refName); // 去得到这个 ref beanthis.beanFactory.registerDependentBean(refName, this.beanName); // 注册return bean;}}catch (BeansException ex) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);}
}

通过调用this.beanFactory.getBean(refName)再次进入Do Get Bean 流程初始化得到该 ref bean;

最后,将解析出来的 Property value 放在一个deepCopy的 ArrayList 列表对象中;顾名思义,就是对值进行了一次深度的拷贝,然后将其作为 bean 的参数,随后开始进行赋值操作);

TypedStringValue 类型解析
这里主要被解析的 Property value 的类型配置为

其 Property value 的值在配置文件中就是一个纯的字符串类型;但从源码中可以知道,Property value 是可以包含 value type 的,所以,在解析 TypedStringValue 的时候,需要根据 value type 进行解析;具体逻辑参考resolveTargetType(typedStringValue);方法。

set property value to bean
此步骤的主流程主要是通过Java Method 反射将解析出来的值赋值给当前的 bean;对应时序图中的 Step 1.8 setPropertyValues

可以看到,通过遍历 deepCopy ArrayList 对象中已经解析过后的 PropertyValue,最终由 BeanWrapperImpl 对象通过方法的反射,将值注入给当前的 bean,Step 1.8.1.2.1.2.2 writeMethod.invoke

BeanWrapperImpl.java 省略了大部分无关紧要的代码,

@Override
public void setValue(final Object object, Object valueToApply) throws Exception{final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :this.pd.getWriteMethod());if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {if (System.getSecurityManager() != null) {AccessController.doPrivileged(new PrivilegedAction<Object>() {@Overridepublic Object run() {writeMethod.setAccessible(true);return null;}});}else {writeMethod.setAccessible(true);}}....writeMethod.invoke(getWrappedInstance(), valueToApply);....
}

通过这一步,将相关的 property populate 给 bean 以后,才算 bean 的实例化完成;

第三件事情:initialize bean
正如流程图中所描述的那样,这个步骤的名字非常然人迷惑,我将流程图中写的备注摘录如下,

“注意, 这里的名称很容易让人产生混淆, 很容易让人产生这样一个疑问, 前面不是已经初始化好了, bean 创建好了, bean 相关的 property 也设置好了, 怎么这里还要进行初始化? 这里其实恰恰充分体现了西方人写代码的严谨, 前面的部分叫做 instantiation, 叫做"实例化”, 而这里叫做 initialization, 叫做 “初始化”; 这样一说, 差不多就明白了, “实例化"就是从 class 得到 instance 的过程; 而"初始化”, 包含的意义更广泛, 其意义包含了"实例化"和其它对 instance 的修饰的过程, 而这里, 其实就是对已经创建好的 bean instance 进行"修饰"的过程。"

所以,这里的 initialize 其实就是对通过 instantiate bean 和 populate bean 两个步骤实例化好的 bean 进行后续必要的修饰;我们通过流程图来看看,它是怎么去修饰的,

通过 AbstractAutowireCapableBeanFactory#initializeBean 方法进行对 bean 的修饰过程,看源码,(删除了大部分不相关的代码)

AbstractAutowireCapableBeanFactory.java

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {invokeAwareMethods(beanName, bean); // 调用实现了 *Aware 接口的方法,比如注入 ApplicationContext...Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 调用 bean-post-processor 的 before initialization 回调方法wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); }try {invokeInitMethods(beanName, wrappedBean, mbd); // 调用 InitializingBean#afterPropertiesSet 回调}catch (Throwable ex) {throw new BeanCreationException((mbd != null ? mbd.getResourceDescription() : null),beanName, "Invocation of init method failed", ex);}if (mbd == null || !mbd.isSynthetic()) {// 调用 bean-post-processor 的 after initialization 回调方法wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }return wrappedBean; // 这里的 wrapped bean 指的是被 bean-post-processor 修饰以后的包装 bean
}

整个过程可以理解为三大块,

注入 Aware 对象,见代码第三行;
回调 bean-post-processors 接口方法,见代码第 9 行和第 23 行;
回调 InitializingBean 接口方法,见代码第 13 行
下面,我们依次来梳理这三个部分;

注入 Aware 对象
对应流程图中的 Step 1.1 invokeAwareMethods,该步骤注册所有实现了Aware接口的 beans

Aware.java

/*** Marker superinterface indicating that a bean is eligible to be* notified by the Spring container of a particular framework object* through a callback-style method. Actual method signature is* determined by individual subinterfaces, but should typically* consist of just one void-returning method that accepts a single* argument.** <p>Note that merely implementing {@link Aware} provides no default* functionality. Rather, processing must be done explicitly, for example* in a {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}.* Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}* and {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}* for examples of processing {@code *Aware} interface callbacks.** @author Chris Beams* @since 3.1*/
public interface Aware {}
从 Aware 接口的注释中可以看到,允许实现了该 Aware 接口的当前 bean 能够有机会通过回调的方式注入 Spring 容器中默认实现了 Aware 接口的 bean,比如 BeanFactory 等;看看源码,AbstractAutowireCapableBeanFactory.javaprivate void invokeAwareMethods(final String beanName, final Object bean) {if (bean instanceof Aware) {if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}if (bean instanceof BeanClassLoaderAware) {((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());}if (bean instanceof BeanFactoryAware) {((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);}}
}

可以看到,注入了三种情况,

当当前 bean 实现了 BeanNameAware 接口,只是调用了 setBeanName;给我目前的感觉是,没有起到什么大的作用,把自己的 beanName 设置给自己,有什么用处?嗯,倒是想到一个,logging;

当当前 bean 实现了 BeanClassLoaderAware 接口,将 Spring 容器的 BeanClassLoader 注入到当前 bean;记住,如果想要获得加载 Bean 当前的 ClassLoader 对象的时候,只需要让 Bean 实现 BeanClassLoaderAware 接口并实现相应接口方法即可。

当当前 bean 实现了 BeanFactoryAware 接口,将 Spring 容器中与 bean 初始化相关的 BeanFactory 实例(这里对应的是 DefaultListableBeanFactory 实例)注册给当前的 bean。
当梳理完这个部分以后,我相信读者会和我一样有这样的疑问,我们不是经常通过Aware的方式注入ApplicaitonContext对象的吗?但和明显,上述的代码并没有注入ApplicationContext对象呀?看如下部分分析,

下列部分是延生部分

但是要特别特别注意的是,这里并没有注入ApplicationContext对象,要注入ApplicaitonContext对象,bean 必须实现ApplicatonContextAware接口;

ApplicationContextAware.java

public interface ApplicationContextAware extends Aware {/*** Set the ApplicationContext that this object runs in.* Normally this call will be used to initialize the object.* <p>Invoked after population of normal bean properties but before an init callback such* as {@link org.springframework.beans.factory.InitializingBean#afterPropertiesSet()}* or a custom init-method. Invoked after {@link ResourceLoaderAware#setResourceLoader},* {@link ApplicationEventPublisherAware#setApplicationEventPublisher} and* {@link MessageSourceAware}, if applicable.* @param applicationContext the ApplicationContext object to be used by this object* @throws ApplicationContextException in case of context initialization errors* @throws BeansException if thrown by application context methods* @see org.springframework.beans.factory.BeanInitializationException*/void setApplicationContext(ApplicationContext applicationContext) throws BeansException;}

从注解中可以看到,它明确标注,是在 populate bean 以后,在 处理 InitializingBean 接口回调 之前调用,那是到底是在什么时刻呢?我们查看下方法 setApplicationContext 方法在 workspace 中的引用,它是在 ApplicationContextAwareProcessor#invokeAwareInterfaces 方法中被调用,而 ApplicationContextAwareProcessor 正好是一个 BeanPostProcessor 对象,所以,ApplicaitonContext对象实际上是在 bean-post-procesor before initialization流程中被注入的,看源码,

ApplicationContextAwareProcessor.java (省略了大部分不相关的代码)

class ApplicationContextAwareProcessor implements BeanPostProcessor {private final ConfigurableApplicationContext applicationContext;private final StringValueResolver embeddedValueResolver;/*** Create a new ApplicationContextAwareProcessor for the given context.*/public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {this.applicationContext = applicationContext;this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());}@Overridepublic Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {AccessControlContext acc = null;....invokeAwareInterfaces(bean);....return bean;}private void invokeAwareInterfaces(Object bean) {if (bean instanceof Aware) {if (bean instanceof EnvironmentAware) {((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware) bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);}}}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {return bean;}}

回调 bean-post-processors 接口方法
先来看看BeanPostProcessor接口的源码,

public interface BeanPostProcessor {/*** Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet*/Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;/*** Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean* initialization callbacks (like InitializingBean's {@code afterPropertiesSet}* or a custom init-method). The bean will already be populated with property values.* The returned bean instance may be a wrapper around the original.* <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean* instance and the objects created by the FactoryBean (as of Spring 2.0). The* post-processor can decide whether to apply to either the FactoryBean or created* objects or both through corresponding {@code bean instanceof FactoryBean} checks.* <p>This callback will also be invoked after a short-circuiting triggered by a* {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,* in contrast to all other BeanPostProcessor callbacks.* @param bean the new bean instance* @param beanName the name of the bean* @return the bean instance to use, either the original or a wrapped one;* if {@code null}, no subsequent BeanPostProcessors will be invoked* @throws org.springframework.beans.BeansException in case of errors* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet* @see org.springframework.beans.factory.FactoryBean*/Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;}

该接口定义了两个回调方法,

Object postProcessBeforeInitialization(Object bean, String beanName)
从方法的注释中不难发现,该方法是在回调 InitializeBean 接口方法之前调用,并且是在 populate bean) 之后进行的调用,通常是对原有 bean 做一层封装,然后返回该封装对象;这就是我在前文所描述的,其实就是是对原有 bean 起到修饰的作用;

Object postProcessAfterInitialization(Object bean, String beanName)
从方法的注释中不难发现,该方法是在回调 InitializeBean 接口方法之前调用,同样也是在 populate bean) 之后进行的调用
所以,bean-post-processors 总共有两次调用的时机,分别是 before initialization 和 after initialization,而且要特别注意的是,该回调方法是针对对容器中所有的普通 bean 进行的回调;

before initialization
该步骤对应 Step 1.2 applyBeanPostProcessorsBeforeInitialization,然后正式调用 Step 1.2.1 beanPostProcessor.postProcessBeforeInitialization bean-post-processor 的回调方法,不过这里要注意的是,如果 Step 1.2.1 返回 null,会终止余下的 post-bean-processor 的执行,并且直接返回一个 null,该 null 同样被视为是封装后的产物,既然是 null,那么后续的 bean-post-processor 也无需处理了,也无法对原有的 bean 进行包装了… 不过,我到觉得这里的 Spring 源码的逻辑应该改进一下,不允许返回 null 的情况,如果返回 null 则报错最好,因为 bean-post-processor 是对原有 bean 进行修饰,是新增属性,而非干掉实例本身… 来看看源码,

AbstractAutowireCapableBeanFactory.java

@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {result = beanProcessor.postProcessBeforeInitialization(result, beanName);if (result == null) {return result;}}return result;
}

如果某个 beanProcessor 处理返回一个 null 则直接返回,并且终止其余的 bean-post-processors

after initialization
对应的是 step 1.4 applyBeanPostProcessorsAfterInitialization 步骤,里面的逻辑和 before initialization 逻辑类似,不再赘述。

回调 InitializingBean 接口方法
该步骤对应的是 Step 1.3: invokeInitMethod,回调 InitializingBean 接口方法,看源码,

AbstractAutowireCapableBeanFactory.java (删除了大部分不相关的代码)

protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)throws Throwable {boolean isInitializingBean = (bean instanceof InitializingBean);if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {if (logger.isDebugEnabled()) {logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");}.....((InitializingBean) bean).afterPropertiesSet();.....}if (mbd != null) {String initMethodName = mbd.getInitMethodName();if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {invokeCustomInitMethod(beanName, bean, mbd);}}
}

可以看到,主要回调的是InitializingBean接口的afterPropertiesSet方法,所以,我们可以让某个 bean 实现 InitializingBean 接口,并通过该接口实现一些当 bean 实例化好以后的回调方法,注意afterPropertiesSet并不返回任何值,所以,这里不是像 bean-post-processor 那样对 bean 起到修饰的作用,而是起到纯粹的调用作用;

总结(我的思考)
以上便是 Spring IoC 容器的核心实现了,容器要达到的最本质的目的就是IoC既反转控制,由容器来负责管理对象实例相关依赖的初始化和注入,而不再是由 bean 自己去控制自己的依赖的初始化和注入过程了;而IoC的实现是通过DI既是依赖注入实现的;也就是为什么上面所介绍的内容都是围绕着 Spring 容器如何实例化一个 bean,如何赋值,如何进行回调等一系列在 bean 的构建声明周期过程中的种种行为;

这样做能达到的好处就是,

实现了对象的依赖属性和依赖对象的高度可定制化,我们可以通过容器配置的方式,轻松的修改 bean 所的依赖对象,以改变原有的其行为;

(这里我突然想到“微内核架构”,Java 的一种内置的依赖注入的方式,通过在 META-INF 中配置接口属性文件,里面其实就是配置的一个接口的实现类,通过它来控制接口在 JVM 中该接口所使用的实现类;但它只是控制某个接口如何在 JVM 中实现,将接口的实现翻转控制了,而 Spring 是对所有的 Class Instance 进行翻转控制,所以一个是站在局部上的反转控制设计,一个是站在全局上的反转控制设计,不可同日而语!)

通过 bean-post-processor 扩展点能够对原始的 bean 进行包装,通过这样的方式,我们可以包装得到一个 proxy bean,提供相关的 AOP 操作,比如提供事务,异常处理等等方法注入的实现;

Spring Beans 初始化流程分析相关推荐

  1. 【Android Camera1】Camera1初始化销毁流程(一) —— 官方Demo初始化流程分析

    Camera1初始化流程 一.摘要 二.Camera1 Demo分析 2.1 变量解析 2.2 构造函数 setUpPreview() adjustCameraParameters() 2.3 Sta ...

  2. 第七章 frr sysrepo纳管初始化流程分析

    本章节主要是通过分析frr sysrepo纳管实现来讲讲frr-7.5是如何实现对sysrepo的支持.以isis协议纳管实现为例.了解本章节的内容需要先了解前面章节的内容.本章节的内容不会过多重复前 ...

  3. 透过源码详解Spring Security 初始化流程

    Spring Security在3.2版本之后支持Java Configuration,即:通过Java编码形式配置Spring Security,可不再依赖XML文件配置,本文采用Java Conf ...

  4. 从web.xml谈谈SpringMVC集成spring的初始化流程及SpringBoot集成SpringMVC

    一.关于servlet 详解servlet,https://www.runoob.com/servlet/servlet-tutorial.html 总览一下: servlet与servlet容器 J ...

  5. android6.0源码分析之Camera API2.0下的初始化流程分析

    1.Camera2初始化的应用层流程分析 Camera2的初始化流程与Camera1.0有所区别,本文将就Camera2的内置应用来分析Camera2.0的初始化过程.Camera2.0首先启动的是C ...

  6. Spring Boot————Spring Boot启动流程分析

    一.引言 Spring Boot 的启动虽然仅仅是执行了一个main方法,但实际上,运行流程还是比较复杂的,其中包含几个非常重要的事件回调机制.在实际生产开发中,有时候也会利用这些启动流程中的回调机制 ...

  7. OSAL初始化流程分析

    我使用的协议栈版本及例子信息: ZigBee2006\Texas Instruments\ZStack-1.4.3-1.2.1\Projects\zstack\Samples\SampleApp    ...

  8. Linphone_android jni下音视频流、初始化流程分析

    本来流程顺序上面做了排版(函数内部的流程,加了tab缩进的)方便理解, 但是发表之后,还是乱了. 流程顺序基本理清了,可以复制到notepad++,手动加下缩进吧. 主流程是序号 1.2.... 函数 ...

  9. Google原生输入法LatinIME引擎初始化流程分析(二)

    引擎初始化首先是在Java层调用native的初始化方法,Java层调用如下: private void initPinyinEngine() {byte usr_dict[];usr_dict = ...

最新文章

  1. hdu4282 x^z+y^z+x*y*z=k 解的个数
  2. “互联网+”促传统企业三大转型
  3. mac mysql 重设密码_Mac下忘记mysql密码重新设置密码的图文教程
  4. Sharepoint学习笔记—ECM系列--4 根据位置设置的默认元数据值(Location-Based Metadata Defaults)
  5. java swing获得焦点_Java Swing TextArea 滚动条并获取焦点
  6. php怎么初始化融云sdk,初始化融云 SDK
  7. Codefroces 760 B. Frodo and pillows
  8. java异常处理(Exception handing)机制
  9. MyBatis,你真的了解了吗
  10. 【图像分类】基于PyTorch搭建LSTM实现MNIST手写数字体识别(单向LSTM,附完整代码和数据集)
  11. 怎么让Html的高度自适应屏幕高度
  12. (转)Unity十大插件
  13. 【离散数学】二元关系中的传递关系与非传递关系
  14. Latex 表格内换行
  15. spring boot新闻管理系统 毕业设计源码211113
  16. 一、dubbo入门与实战
  17. 13 款开源的全文检索引擎
  18. css特效实现透明渐变
  19. 一文解读广告投放全攻略,提升拓客效率
  20. 条码的开发使用介绍文档

热门文章

  1. MATLAB数据分析
  2. Ubuntu 14.04 LTS 下升级 gcc 到 gcc-4.9、gcc-5 版本
  3. Cadence元器件库
  4. 使用UltraEdit来拷贝粘贴二进制
  5. python可以做二维码吗_Python制作二维码,并且可以添加logo
  6. shell tr 替换 空格_Shell 字符串分隔符!!!(全网最详细总结)
  7. mysql 设置字段自动增长值_mysql命令行脚本
  8. php截取字符串函数 左右,php截取中文字符串函数的技巧
  9. Unity 2017 Game Optimization 读书笔记 Dynamic Graphics(1)
  10. 如何批量转化成jpg格式_heic图片格式快速转换jpg,批量转换方法