【Spring Bean 生命周期系列】传送门
1、Spring Bean生命周期: Bean元信息的配置与解析阶段
2、Spring Bean生命周期: Bean的注册
3、Spring Bean生命周期: BeanDefinition的合并过程
4、Spring Bean生命周期: Bean的实例化
5、Spring Bean生命周期:属性赋值阶段
6、Spring Bean生命周期:Bean的初始化阶段
写在前面
注:本文章使用的 SpringBoot 版本为 2.2.4.RELEASE,其 Spring 版本为 5.2.3.RELEASE
接着上节继续分析,上节说了Bean属性赋值的过程,这节就聊一下初始化Bean的过程
initializeBean
方法主要有四块内容
下面我们就按照这个顺序跟着源码逐块分析
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
//如果当前Bean实现了BeanNameAware,则将beanName通过回调传给当前Bean
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
//如果当前Bean实现了BeanClassLoaderAware,则将BeanClassLoader通过回调传给当前Bean
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
//如果当前Bean实现了BeanFactoryAware,则将BeanFactory通过回调传给当前Bean
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
这个方法主要实现了BeanNameAware
、BeanClassLoaderAware
、BeanFactoryAware
三个Aware接口的回调。
下面就举例演示下
public class BeanAwareDemo implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(BeanAwareDemo.class);
context.refresh();
BeanAwareDemo bean = context.getBean(BeanAwareDemo.class);
System.out.println("beanFactory==>" + bean.beanFactory);
System.out.println("beanName==>" + bean.beanName);
System.out.println("classLoader==>" + bean.classLoader);
context.close();
}
private ClassLoader classLoader;
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
private String beanName;
@Override
public void setBeanName(String name) {
this.beanName = name;
}
}
输出结果:
beanFactory==>org.springframework.beans.factory.support.DefaultListableBeanFactory@458c1321
beanName==>beanAwareDemo
classLoader==>sun.misc.Launcher$AppClassLoader@18b4aac2
看到这可能有同学会想:“那我平时经常用的ApplicationContextAware
是什么时候,在哪里被回调的呢?”
我:别着急,剩下的一些常用Aware接口的回调时机、在哪里回调,我们先不再这里展开了,以后有时间了单独拿出来讨论。
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
//省略分析过的代码
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//初始化前回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//执行初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
//省略异常信息
}
if (mbd == null || !mbd.isSynthetic()) {
//初始化后回调
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
这里呢,为了方便说明,将Bean初始化前后放到一起来分析了。
经过我们前面章节的分析,我们对BeanPostProcessor
这个后置处理器也有了一些认识了。主要是通过postProcessBeforeInitialization
、postProcessAfterInitialization
两个方法在Bean初始化前与后对Bean进行些修饰。
一起来看下这两个方法吧!
//初始化前回调
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
//将原始Bean对象存一份
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
// 如果有回调函数 返回null了,那么依然使用原始的Bean对象
if (current == null) {
return result;
}
//如果不返回null,则将返回值作为当前Bean对象,接着进行循环处理
result = current;
}
return result;
}
//初始化后回调
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
//将原始Bean对象存一份
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
// 如果有回调函数 返回null了,那么依然使用原始的Bean对象
if (current == null) {
return result;
}
//如果不返回null,则将返回值作为当前Bean对象,接着进行循环处理
result = current;
}
return result;
}
这里不再给出栗子了,有兴趣的小伙伴可以去BeanPostProcessor浅析看一下
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
//判断当前Bean是否实现了InitializingBean
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
//省略日志输出
//if条件成立 是Java安全代码逻辑可忽略,与else代码段实质操作一致
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 如果Bean实现了InitializingBean,那么这里回调afterPropertiesSet方法
((InitializingBean) bean).afterPropertiesSet();
}
}
//如果mbd不为空 且bean类型不是NullBean
if (mbd != null && bean.getClass() != NullBean.class) {
//获取InitMethod方法名
String initMethodName = mbd.getInitMethodName();
//条件成立:1、存在initMethod方法 2、当前Bean不是InitializingBean或initMetodName不等于afterPropertiesSet 3、不是外部管理的initMethods
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// 那么执行自定义InitMethod方法,根据方法名获取Method 反射调用
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
上面给出了afterPropertiesSet
、initMethod
两个初始化方法的调用过程及调用顺序,这里的initMethod
与@Bean中initMethod属性是一致的。
有的小伙伴可能会说了:“那我平时还经常使用一种别的初始化方法呢?是用@PostConstruct
”标注的,它不是在这里被调用吗?那它是在哪里被调用的?"
我: 还记得BeanPostProcessor浅析章节吗? 我们在那个章节介绍了一些常用的BeanPostProcessor,其中@PostConstruct就是在CommonAnnotationBeanPostProcessor
被调用的。
其实CommonAnnotationBeanPostProcessor
继承自InitDestroyAnnotationBeanPostProcessor
,确切地说是两个类联合起来完成对@PostConstruct的解析和方法调用
还记得上面 初始化前回调函数的调用吗?没错,无论是对@PostConstruct的解析和方法调用均发生在postProcessBeforeInitialization
。我们简单地梳理下
InitDestroyAnnotationBeanPostProcessor
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//这里的元信息主要收集目标Bean中标注了@PostConstruct和@PreDestroy注解的方法
LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
try {
// 这里以反射方式直线初始化方法的调用
metadata.invokeInitMethods(bean, beanName);
}
catch (InvocationTargetException ex) {
throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
}
return bean;
}
上面分析了@PostConstruct
、afterPropertiesSet
及initMethod
初始化方法的调用过程,那么小伙伴 如果同一个Bean中同时有着三个初始化方法,那它们的调用顺序是怎样的呢?
答:其实通过我们的分析就可以推断出了,@PostConstruct
标注的初始化方法发生在初始化前回调函数阶段,afterPropertiesSet
和initMethod
则发生在初始化阶段,并且afterPropertiesSet
的调用先于initMethod
。因此三者的调用顺序是@PostConstruct
>afterPropertiesSet
>initMethod
以上就是本章讨论的主要内容了,如您在阅读过程中发现有错误,还望指出,感谢!