initializeBean是进行bean初始化的,主要做了三件事:
1.激活 Aware 方法
2.后置处理器的应用
3.激活自定义的 init 方法
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) { // 安全模式
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
// <1> 激活 Aware 方法,对特殊的 bean 处理:Aware、BeanClassLoaderAware、BeanFactoryAware
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
// 后处理器,before
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 激活用户自定义的 init 方法
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// 后处理器,after
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
1 invokeAwareMethods 方法
Aware 是一个空接口,具体的接口定义由子类实现,通常用于属性设置。比如BeanNameAware(setBeanName),ApplicationContextAware(setApplicationContext)。功能的实现主要在invokeAwareMethods方法中。
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);
}
}
}
当bean实现了BeanNameAware,BeanClassLoaderAware,BeanFactoryAware三个接口时,就会在bean初始化的时候去调用对应的set方法,设置对应的属性。
2 BeanPostProcessor 接口
public interface BeanPostProcessor {
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
该接口允许在bean初始化的前后对bean做定制化的修改,最常见的应用就是AOP的实现。
一般普通的 BeanFactory 是不支持自动注册 BeanPostProcessor 的,需要我们手动调用 addBeanPostProcessor() 进行注册,注册后的 BeanPostProcessor 适用于所有该 BeanFactory 创建的 bean(通过beanFactory获取对应类型的bean),但是 ApplicationContext 可以在其 bean 定义中自动检测所有的 BeanPostProcessor 并自动完成注册,同时将他们应用到随后创建的任何 bean 中(spring通过main方法启动容器)。
// 后处理器,before
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 激活用户自定义的 init 方法
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
// 后处理器,after
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
BeanPostProcessor 主要是它的两个方法,在bean的初始化前后去对类做操作。
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
// 获取 BeanPostProcessor 数组
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 循环调用 postProcessAfterInitialization 方法,如果为空立即返回
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
从wrappedBean,这个对象的命名也能看出这是这是对bean做包装。
BeanPostProcessor 已经分析完毕了,这里简单总结下:
- BeanPostProcessor 的作用域是容器级别的,它只和所在的容器相关 ,当 BeanPostProcessor 完成注册后,它会应用于所有跟它在同一个容器内的 bean。
- BeanFactory 和 ApplicationContext 对 BeanPostProcessor 的处理不同,ApplicationContext 会自动检测所有实现了 BeanPostProcessor 接口的 bean,并完成注册,但是使用 BeanFactory 容器时则需要手动调用 addBeanPostProcessor() 完成注册
- ApplicationContext 的 BeanPostProcessor 支持 Ordered,而 BeanFactory 的 BeanPostProcessor 是不支持的,原因在于ApplicationContext 会对 BeanPostProcessor 进行 Ordered 检测并完成排序,而 BeanFactory 中的 BeanPostProcessor 只跟注册的顺序有关。
3 init-method方法
在研究这个方法前,有必要先看看InitializingBean接口
public interface InitializingBean {
/**
* 在bean设置完所有的属性后,允许对bean的属性再次修改
*/
void afterPropertiesSet() throws Exception;
}
继续看看init-method方法的代码
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// 是否实现了 InitializingBean 接口
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
// 直接调用 afterPropertiesSet()
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
// 判断是否指定了 init-method(),
// 如果指定了 init-method(),则再调用制定的init-method
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
两种方式初始化bean对象,第一种就是bean实现了InitializingBean接口,然后容器会调用它的afterPropertiesSet方法进行初始化,其次就是init-method方法。
init-method 方法是在xml配置文件中<bean>标签的一个属性,有两种配置方式
<bean id="lifecycleMethodsDisabled" class="org.springframework.beans.factory.xml.DefaultLifecycleMethodsTests$LifecycleAwareBean"
init-method="" destroy-method=""/>
全局默认配置的default-init-method
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lang="http://www.springframework.org/schema/lang"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/lang
https://www.springframework.org/schema/lang/spring-lang-3.1.xsd"
default-autowire="byName"
default-init-method="startup"
default-destroy-method="shutdown">
总的来说两种方式各有利弊InitializingBean接口的方式对代码有侵入性,init-method的方式因为现在基本已经抛弃了XML配置,所以很少用到。