再谈BeanPostProcessor
上篇文章介绍的是BeanPostProcessor的用法,在最后留下了一个问题,对于Spring中的Bean属性'Lazy-init'(延迟加载),当Hook类(BeanPostProcessorApp)或被Hook的类(App)具有这个属性时,会有什么样的表现。
1.接着前面文章的已有的配置,首先我们分别在App和BeanPostProcessorApp上增加构造函数,并且打印一句话:
private App(){
System.out.println("App.App()");
}
private BeanPostProcessorApp(){
System.out.println("BeanPostProcessorApp.BeanPostProcessorApp()");
}
同时在BeanPostProcessorApp中增加一个after方法(上篇只用到了before):
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if(bean instanceof App){
((App)bean).setSays("After:BeanPostProcessorApp");
}
return bean;
}
然后执行BeanPostProcessorAppTest方法,打印的结果如下:
BeanPostProcessorApp.BeanPostProcessorApp()
App.App()
App.app():After:BeanPostProcessorApp
2.我们调式看一下三条信息分别在什么情况下产生:
1)刚才的第一条信息 “BeanPostProcessorApp.BeanPostProcessorApp() ”是在registerBeanPostProcessors()方法中产生的,也就是说该BeanPostProcessorApp的初始化是在所有BeanPostProcessor注册的时候就进行了。
而这个时候Bean的实例化还没有开始,所以得出这样的结论:
在实现BeanPostProcessor的接口的Bean中增加lazy-init属性是无效的,因为这个Bean在未进行初始化的时候已经被上面的registerBeanPostProcessors初始化了;结合本例,也就是说下面的写法是无效的:
2)再看第二条信息,因为没有设置lazy-init属性,所以在finishBeanFactoryInitialization()方法中就进行了初始化并且创建了实例,如下:
3)最后一条信息则是这样产生的,因为我们在注册BeanPostProcessor的时候已经把我们自己的BeanPostProcessorApp注册了,同时在执行finishBeanFactoryInitialization方法进行Bean的初始化的时候会执行org.springframework.beans.factory.support.AbstractBeanFactory中的getBean方法(上一篇已经介绍了),创建一个实例,进行真正的注入,而我们的
<span style="font-family:SimSun;">App app = (App)applicationContext.getBean("app");</span>
只是得到其中一个引用,最后打印信息。
3.上面分析的结论是,在实现BeanPostProcessor的接口的Bean中增加lazy-init属性是无效的,可以自己实例验证一下,这里就不贴上了;继续分析,如果我们给Bean App增加lazy-init这个属性呢?,如下:
我们可以猜测,因为加上lazy-init属性之后,就不会在Spring的初始化过程中实例化;在org.springframework.beans.factory.support.DefaultListableBeanFactory(上一篇提到过)中我们可以看到,实际上是没有执行org.springframework.beans.factory.support.AbstractBeanFactory的getBean方法:
而这个org.springframework.beans.factory.support.AbstractBeanFactory中的getBean方法实际上是执行了“实例化”+"BeanPostProcessor"这两个功能。
所以猜测1:加载完Spring配置文件不会有第二条信息。
由于我们写的getBean其实就是org.springframework.beans.factory.support.AbstractBeanFactory中的getBean,如下:
所以猜测2:执行完自己的getBean就会进行初始化,并且执行BeanPostProcessor的实现;
验证如下:
如上,证实了猜测1
如上图,在未执行第三个断点says方法之前,says的值已经改变,证实了猜测2.