共计 6225 个字符,预计需要花费 16 分钟才能阅读完成。
本篇内容介绍了“Spring 的 Aware 注入源码分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
Aware 注入
在使用 Spring 的时候我们将自己的 Bean 实现 BeanNameAware 接口、BeanFactoryAware 接口等,依赖容器帮我们注入当前 Bean 的名称或者 Bean 工厂,其代码实现的 initializeBean 方法:
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction Object () {
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
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()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
看一下上面第 5 行的实现:
private void invokeAwareMethods(final String beanName, final Object bean) {
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 方法、如果 bean 是 BeanClassLoaderAware 接口的实现类会调用 setBeanClassLoader 方法、如果是 BeanFactoryAware 接口的实现类会调用 setBeanFactory 方法,注入对应的属性值。
调用 BeanPostProcessor 的 postProcessBeforeInitialization 方法
上面 initializeBean 方法再看 16 行其实现:
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;
}
遍历每个 BeanPostProcessor 接口实现,调用 postProcessBeforeInitialization 方法,这个接口的调用时机之后会总结,这里就代码先简单提一下。
调用初始化方法
initializeBean 方法的 20 行,调用 Bean 的初始化方法,看一下实现:
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 +
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction Object () {
public Object run() throws Exception {
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null !(isInitializingBean afterPropertiesSet .equals(initMethodName))
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
看到,代码做了两件事情:
1、先判断 Bean 是否 InitializingBean 的实现类,是的话,将 Bean 强转为 InitializingBean,直接调用 afterPropertiesSet() 方法
2、尝试去拿 init-method,假如有的话,通过反射,调用 initMethod
因此,两种方法各有优劣:使用实现 InitializingBean 接口的方式效率更高一点,因为 init-method 方法是通过反射进行调用的;从另外一个角度讲,使用 init-method 方法之后和 Spring 的耦合度会更低一点。具体使用哪种方式调用初始化方法,看个人喜好。
调用 BeanPostProcessor 的 postProcessAfterInitialization 方法
最后一步,initializeBean 方法的 29 行:
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
同样遍历 BeanPostProcessor,调用 postProcessAfterInitialization 方法。因此对于 BeanPostProcessor 方法总结一下:
1、在初始化每一个 Bean 的时候都会调用每一个配置的 BeanPostProcessor 的方法
2、在 Bean 属性设置、Aware 设置后调用 postProcessBeforeInitialization 方法
3、在初始化方法调用后调用 postProcessAfterInitialization 方法
注册需要执行销毁方法的 Bean
接下来看一下最上面 doCreateBean 方法的第 83 行 registerDisposableBeanIfNecessary(beanName, bean, mbd) 这一句,完成了创建 Bean 的最后一件事情:注册需要执行销毁方法的 Bean。
看一下方法的实现:
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, RootBeanDefinition mbd) {
AccessControlContext acc = (System.getSecurityManager() != null ? getAccessControlContext() : null);
if (!mbd.isPrototype() requiresDestruction(bean, mbd)) {
if (mbd.isSingleton()) {
// Register a DisposableBean implementation that performs all destruction
// work for the given bean: DestructionAwareBeanPostProcessors,
// DisposableBean interface, custom destroy method.
registerDisposableBean(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
else {
// A bean with a custom scope…
Scope scope = this.scopes.get(mbd.getScope());
if (scope == null) {
throw new IllegalStateException(No Scope registered for scope + mbd.getScope() +
}
scope.registerDestructionCallback(beanName,
new DisposableBeanAdapter(bean, beanName, mbd, getBeanPostProcessors(), acc));
}
}
}
其中第 3 行第一个判断为必须不是 prototype(原型)的,第二个判断 requiresDestruction 方法的实现为:
protected boolean requiresDestruction(Object bean, RootBeanDefinition mbd) {
return (bean != null
(bean instanceof DisposableBean || mbd.getDestroyMethodName() != null ||
hasDestructionAwareBeanPostProcessors()));
}
要注册销毁方法,Bean 需要至少满足以下三个条件之一:
(1)Bean 是 DisposableBean 的实现类,此时执行 DisposableBean 的接口方法 destroy()
(2)Bean 标签中有配置 destroy-method 属性,此时执行 destroy-method 配置指定的方法
(3)当前 Bean 对应的 BeanFactory 中持有 DestructionAwareBeanPostProcessor 接口的实现类,此时执行 DestructionAwareBeanPostProcessor 的接口方法 postProcessBeforeDestruction
在满足上面三个条件之一的情况下,容器便会注册销毁该 Bean,注册 Bean 的方法很简单,见 registerDisposableBean 方法实现:
public void registerDisposableBean(String beanName, DisposableBean bean) {
synchronized (this.disposableBeans) {
this.disposableBeans.put(beanName, bean);
}
}
容器销毁的时候,会遍历 disposableBeans,逐一执行销毁方法。
“Spring 的 Aware 注入源码分析”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!