這篇文章很重要,講解的是動態代理,以及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();每一次執行方法時都會被動態代理所攔截,從而執行了三次動態代理。