Spring 源码梳理(二) BeanPostProcessor

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同时延迟加载或者任意一个延迟加载的情况,先思考,后面再进行分析。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章