BeanPostProcessor
1.BeanPostProcessor的概念
BeanPostProcessor是一个接口,它可以使得继承它的类成为一个"回调类"(自己起的称呼),继承的方法成为回调函数;它就像Windows中Hook Api ,就是一个钩子函数,先注册这个函数,且指定一个事件目标;那么当一个事件在执行前或者后时,就会触发这个函数的执行,可以在这个事件的前后做一些操作,影响这个事件。BeanPostProcessor就是这样的作用,它可以在类的初始化前后改变这个类的属性,从而影响实体类。
2.下面实际操作这个接口(接着上一篇已定义好的类)
1)调试准备
改变App类,改变后如下:
package com.mycompany.app;
public class App
{
private String says="App";
public String getSays() {
return says;
}
public void setSays(String says) {
this.says = says;
}
public void say(){
System.out.println("App.app():"+says);
}
}
新增BeanPostProcessorApp类:
package com.mycompany.app;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class BeanPostProcessorApp implements BeanPostProcessor{
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if(bean instanceof App){
((App)bean).setSays("BeanPostProcessorApp");
}
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
}
Spring配置文件中增加:
<bean id="beanPostProcessorApp" class="com.mycompany.app.BeanPostProcessorApp"></bean>
新增BeanPostProcessorApp的测试类:
package com.mycompany.app;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class BeanPostProcessorAppTest {
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("SpringBean.xml");
App app = (App)applicationContext.getBean("app");
app.say();
}
}
2)调试如下:
首先进入refresh函数,上一篇已经提到了,这篇主要涉及refresh中的下面两个方法,registerBeanPostProcessors用来注册这个Hook函数,finishBeanFactoryInitialization是对配置文件中非延迟加载的bean进行实例化,如下图:
A:先分析registerBeanPostProcessors这个函数,我们调式进去看一下,首先会进入org.springframework.context.support中的
PostProcessorRegistrationDelegate类,然后到了registerBeanPostProcessors方法,如下图:
这个方法会把刚才的BeanPostProcessorApp注册到beanFactory中,然后我们就会在beanFactory中看到beanPostProcessors多了一个我们自己的BeanPostProcessorApp,下图所示:
到此,这个钩子已经注册完成,当对类进行实例化的时候就会调用该钩子函数;
B:然后分析finishBeanFactoryInitialization函数,它主要是对bean进行初始化,调用顺序如下:
(1).org.springframework.context.support.AbstractApplicationContext中的
(2).org.springframework.beans.factory.support.DefaultListableBeanFactory中的
(3).org.springframework.beans.factory.support.AbstractBeanFactory中的
(4).org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中的
(5).org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中的
(6).org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory中的
(7).先进入applyBeanPostProcessorsBeforeInitialization:
由于beanPostProcessor有多个(之前已经看到了,除了我们自己的“BeanPostProcessorApp”,还有几个暂不知其意,以后遇到再进行分析), 所以会找这些processors的postProcessBeforeInitialization方法实现, 当for循环到我们的processor时,就会执行
我们自己写的方法:
自己的方法:
到此就完成了我们的目的,对App这个类,进行Hook,而且已经改变了实体类App的says的值。最后当我们进行getBean("app")的操作时,我们进行打印结果如下:
<span style="font-family:SimSun;font-size:18px;"><span style="font-family:Arial Black;">App.app():BeanPostProcessorApp</span></span>
同样的,After的操作同Before一样;注:
上面的bean的初始化,是在读取配置文件的时候进行的; 如果是延迟加载的情况,是否能够Hook成功呢。 对于App和BeanPostProcessorApp同时延迟加载或者任意一个延迟加载的情况,先思考,后面再进行分析。