本文是笔者阅读Spring源码的记录文章,由于本人技术水平有限,在文章中难免出现错误,如有发现,感谢各位指正。在阅读过程中也创建了一些衍生文章,衍生文章的意义是因为自己在看源码的过程中,部分知识点并不了解或者对某些知识点产生了兴趣,所以为了更好的阅读源码,所以开设了衍生篇的文章来更好的对这些知识点进行进一步的学习。
这篇文章是 Spring源码分析五 :bean的获取③ - getSingleton 的文章的展开内容。Spring 在 AbstractAutowireCapableBeanFactory#doCreateBean
方法中,完成了bean的完整创建。而在上篇 Spring源码分析七:bean的属性注入⑤ - populateBean 中,完成了Bean的属性注入,表面上看起来 Bean的创建过程已经结束了。实际上还有一些收尾工作没有完成。本文就是完成Bean创建的收尾工作:完成 Aware 接口的功能,调用后处理器的Bean的后置方法,以及指定的init 方法的激活。。
本文的分析代码在 AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)
方法中。
到这一步,创建bean的过程已经经过了
createBeanInstance
: 通过反射或者代理创建bean实例populateBean
: 给bean注入属性实例。相较于前几篇的内容,本文的内容显得简单了很多。具体代码如下:
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
// 对特殊的bean进行处理 : 实现了 Aware、BeanClassLoaderAware、BeanFactoryAware 的处理。后面详解
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
// 激活 Aware 方法
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 调用了bean后处理器的方法
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 激活自定义的init的方法。
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 调用bean后处理器的方法
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
上面关于两个后处理器的调用,本文就不再赘述了,分别调用了 BeanPostProcessor. postProcessBeforeInitialization
、BeanPostProcessor.postProcessAfterInitialization
方法。
对后处理器比较感兴趣的可以看衍生篇:
所以我们主要分析下面两个方法 :
这个方法很简单,完成了 Aware 接口的激活功能。可以简单的说 :
BeanNameAware
接口,则将 beanName设值进去BeanClassLoaderAware
接口,则将 ClassLoader 设值进去BeanFactoryAware
接口,则将 beanFactory 设值进去 private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
这里简单解释一下 Aware的作用。从上面的代码可以看到,实现不同类型的 Aware 接口会接受到不同得到初始化数据。
举个例子: 如果bean实现了 BeanFactoryAware
接口,那么他就可以在bean内部获取到beanFacotory。
其实Aware
接口的作用 我在分析 AutowiredAnnotationBeanPostProcessor
后处理器的时候才突然想明白的。 AutowiredAnnotationBeanPostProcessor
中完成了Bean的属性和方法注入,属性要从BeanFactory
的缓存中获取,那么AutowiredAnnotationBeanPostProcessor
如何得到的beanFactory呢? 答案是实现了BeanFactoryAware
接口。这样在 AutowiredAnnotationBeanPostProcessor
初始化的时候就通过
void setBeanFactory(BeanFactory beanFactory)
获取到beanFactory。如下图。AutowiredAnnotationBeanPostProcessor
保存了setBeanFactory 带来的beanFactory,并通过此来从容器中获取需要的bean。
首先需要注意的是,Bean 的初始化方法除了可以使用 init-method
属性(或者 @Bean(initMethod=''”)
),还可以通过实现InitializingBean
接口,并且在afterPropertiesSet
方法中实现自己初始化的业务逻辑。
调用顺序则是 afterPropertiesSet
先调用,后面调用 init-method
指定的方法。这一点从下面的代码逻辑就能看到。
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 首先检查是否是InitializingBean,如果是的话则需要调用 afterPropertiesSet 方法。
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
// 调用 afterPropertiesSet 方法
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
// 从RootBeanDefinition 中获取initMethod 方法名称
String initMethodName = mbd.getInitMethodName();
// 调用initMethod 方法。
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
相较于之前的分析流程,initializeBean 方法是真的简单。流程也比较清楚。
以上:内容部分参考
《Spring源码深度解析》
如有侵扰,联系删除。 内容仅用于自我记录学习使用。如有错误,欢迎指正