04Spring_bean 后處理器(后處理Bean),BeanPostProcessor ,bean創建時序,動態代理


這篇文章很重要,講解的是動態代理,以及bean創建前后的所發生的事情。介紹一個接口:在Spring構造Bean對象過程中,有一個環節對Bean對象進行 后處理操作 (鈎子函數) ----- Spring 提供 BeanPostProcessor 接口。我們可以自定義類,實現 BeanPostProcessor 接口,配置到Spring容器中,在構造對象時,spring容器會調用接口中方法。

這個接口兩個方法public Object postProcessAfterInitialization(Object bean, String beanName) 方法以及public Object postProcessBeforeInitialization(final Object bean, String beanName) 這兩個方法里面的bean就是spring IO容器創建對象,beanName就是Sring配置文件applicationContext.xml文件里面對應的bean id。

為了說明postProcessBeforeInitialization和postProcessAfterInitialization的具體調用順序,舉一個例子說明。

//applicationContext.xml
<bean id="teacherService" class="cn.csdn.cyclelife.TeacherService"  init-method="init" destroy-method="destroy">
 <constructor-arg type="java.lang.Integer" index="0">
 <value>20</value>
  </constructor-arg>
 <property name="name">
 <value>Longmanfei</value>
 </property>
 </bean>
<bean id="postService"class="cn.csdn.cyclelife.PostService"></bean>
//TeacherService bean
public class TeacherService {

    private String name;
 
    private Integer age;
	
	
	public void setName(String name){
		System.out.println("----這是teacherservice的set方法----");
		this.name=name;
	}
	
	public TeacherService(Integer age){
		this.age=age;
	}
	

	public void init(){
		System.out.println("--------這是teacherservice的init的方法-------------");
	}
	
	public void destroy(){
		System.out.println("---------這是銷毀(destroy)方法----------");
	}
	
	public void display(){
		System.out.println(this.name+"-----------------"+this.age);
	}
 }
// 實現接口的BeanPostProcessor bean 
 public class PostService implements BeanPostProcessor{

	
	/**在初始化之后調用這個方法*/
	@Override
	public Object postProcessAfterInitialization(Object bean, String arg1)
			throws BeansException {
		System.out.println("----這是init之后執行的方法postProcessAfterInitialization----");
		return bean;
	}

	/**在初始bean之前調用的這個方法 在init方法之前執行,在set方法之后*/
	@Override
	public Object postProcessBeforeInitialization(Object bean, String arg1)
			throws BeansException {
		/**instanceof 判斷前者是否是后者的一個實例*/
		if(bean instanceof TeacherService){
			System.out.println("--這是在init之前進行修改bean的屬性值--");
			/*這里我們不能直接new一個對象 因為bean本身就是一個對象,直接轉換就可以了*/
			((TeacherService)bean).setName("Longmanfei");
		}
	    System.out.println("---這是init之前執行的方法postProcessBeforeInitialization---");
		return bean;
	}
}
//Junit 測試方法
public class App {
	
	
	@Test
	public void test1(){
		/**加載容器*/
		ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"applic*.xml"});
		/**調用getbean方法*/
		TeacherService ts = (TeacherService) ac.getBean("teacherService");
		
		
		ts.display();
		
		/**調用close方法關閉bean*/
		AbstractApplicationContext aac =(AbstractApplicationContext) ac;
		aac.close();
	}

}
//這是執行結果(當加載容器的時候會判斷是否有實現接口的BeanPostProcessor bean,如果有其他Bean就會按照特定的順序去執行,並且執行實現接口的bean里的方法)
----這是teacherservice的set方法----
--這是在init之前進行修改bean的屬性值--
----這是teacherservice的set方法----
---這是init之前執行的方法postProcessBeforeInitialization---
--------這是teacherservice的init的方法-------------
----這是init之后執行的方法postProcessAfterInitialization----
Longmanfei-----------------20
---------這是銷毀(destroy)方法----------

 

這個例子里面可以看到Spring先會創造bean的實例對象,然后調用postProcessBeforeInitialization,然后再調用init-method="init"方法,然后再調用postProcessAfterInitialization方法。

這里我給一個bean的創建流程圖

這個圖對上面的例子的代碼運行結果給出了很好的解釋。(這個博客非常不錯http://uule.iteye.com/blog/2094609)

換句話說我們在執行public Object postProcessBeforeInitialization(final Object bean, String beanName)方法時,傳入的值bean就是IOC容器已經給我們創建好的對象了,

那么我們可以拿這個對象做什么呢?很重要的一點就是動態代理,我們可以給這個bean對象做個動態代理。

先給出具體代碼我在做分析:

做動態代理必須要接口,所以我先給出抽象角色(接口)

package cn.itcast.spring.d_lifecycle;

public interface IHello {
    public void sayHello();

    public void setup();

    public void teardown();
}

 

再給出真實角色:

package cn.itcast.spring.d_lifecycle;

/**
 * Bean對象,初始化和銷毀方法 (無返回值、無參數、非靜態)
 * 
 * @author seawind
 * 
 */
public class LifeCycleBean implements IHello {
    public LifeCycleBean() {
        System.out.println("LifeCycleBean 構造...");
    }
//配置文件中init-method="setup"
    public void setup() {
        System.out.println("LifeCycleBean 初始化...");
    }
//配置文件中destroy-method="teardown"
public void teardown() {
System.out.println(
"LifeCycleBean 銷毀...");
}
//被代理的方法
@Override
public void sayHello()
{

System.out.println(
"hello ,itcast...");

}
}

再給出實現了BeanPostProcessor接口的方法:

package cn.itcast.spring.d_lifecycle;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * 后處理器
 * 
 * @author seawind
 * 
 */
public class MyBeanPostProcessor implements BeanPostProcessor {
    static int a=0;
    @Override
    /**
     * bean 代表Spring容器創建對象
     * beanName 代表配置對象對應 id屬性
     */
    
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("lifeCycleBean")) {
            System.out.println("后處理器 初始化后執行...");
        }
        return bean;
    }

    @Override
    public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
        // 針對bean id 為 lifeCycleBean的對象 進行代理,配置文件中bean的id為lifeCycleBean就做一下處理
        if (beanName.equals("lifeCycleBean")) {
            System.out.println("后處理器 初始化前執行...");
/*給傳進來的bean對象做一個動態代理.bean.getClass().getClassLoader表示要被執行代理的類,也就是我們的IOC容器創建的bean對象。
bean.getClass().getInterfaces()表示我們的要代理的類所實現
的所有的而接口,我們最后new出來的代理類會按照這個參數實現這些所有的接口。這也是為什么動態代理模式必須要用接口的原因了。
new InvocationHandler() {}表示真正要執行的方法。
最后用的是return 就是把生成出來的的代理類返回了。所以執行好這個方法后其實的返回的是new 出來的的代理類,而不是之前的bean對象了。(這句話非常重要)
*/
return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //模擬代理方法(額外要執行的方法)
System.out.println("執行代理.....");
//執行要真正的方法 return method.invoke(bean, args); } }); }
return bean; } }

再給出Spring的配置文件(applicationContext.xml)

<bean id="lifeCycleBean" class="cn.itcast.spring.d_lifecycle.LifeCycleBean" 
        init-method="setup" destroy-method="teardown" />

最后給出Junit的測試代碼

package cn.itcast.spring.d_lifecycle;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class LifeCycleTest {
    @Test
    public void testInitDestroy() {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        IHello lifeCycleBean = (IHello) applicationContext.getBean("lifeCycleBean");
        System.out.println(lifeCycleBean);
        lifeCycleBean.sayHello();

        // 必須手動調用 容器銷毀的方法 --- web服務器tomcat,自動調用容器銷毀
        applicationContext.close();
    }
}

 

對上面代碼的分析:經過public class MyBeanPostProcessor implements BeanPostProcessor里面的postProcessBeforeInitialization方法后,就是給IOC創建的bean對象進行了動態代理,在Junit的測試代碼中。我們執行了 lifeCycleBean.sayHello();就會被動態代理給攔截,執行 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {......}里面的方法.這里的lifeCycleBean已經不是lifeCycleBean.class類型了,而是com.sun.proxy.$Proxy4類型了,要驗證這個觀點很簡單,只要在public class LifeCycleTest 方法中的 lifeCycleBean.sayHello();之前加一句System.out.println(lifeCycleBean);就可以得到驗證。

最后給出上述代碼的是運行結果:

后處理器 初始化前執行...
執行代理.....
被代理的方法是public abstract void cn.itcast.spring.d_lifecycle.IHello.setup()a的值是1aaaaacn.itcast.spring.d_lifecycle.LifeCycleBeanLifeCycleBean 初始化...
后處理器 初始化后執行...
執行代理.....
被代理的方法是public java.lang.String  java.lang.Object.toString()

aaaaacn.itcast.spring.d_lifecycle.LifeCycleBeancn.itcast.spring.d_lifecycle.LifeCycleBean@a0430b6
測試方法中lifeCycleBean的真相是com.sun.proxy.$Proxy4執行代理.....

被代理的方法是public abstract void cn.itcast.spring.d_lifecycle.IHello.sayHello()a的值是3aaaaacn.itcast.spring.d_lifecycle.LifeCycleBeanhello ,itcast...

這里很奇怪,為什么執行了這么多的“執行代理” 原因很簡單,因為setup() System.out.println(lifeCycleBean)和 lifeCycleBean.sayHello();每一次執行方法時都會被動態代理所攔截,從而執行了三次動態代理。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM