一、動態代理:
1.在原有的靜態代理的基礎上進一步的完善,由於靜態代理中,重復寫了相同的代碼使得代碼的整體結構顯得冗余,而且還不同的核心類還需要有不用的代理類,是寫死了的具體的類。所以需要使用動態代理來代替靜態代理。
2.具體實例:
⑴、業務介紹:
假定高三學生為核心類,學生的家人是代理類。高三學生需要做的核心業務有:在家學習(studyAtHome)、在學校學習(studyAtHome);家人需要做的非核心業務為:准備飯菜(買、洗、炒、煮飯)。准備補品(購買、熬制、加佐料)。
⑵、創建一個高三學生接口:G3Student
package aop_002; //首先定義一個接口,用來高三學生來是實現, //在這個接口中聲明一個在家學習和一個在學校學習的方法 public interface G3Student { public void studyAtHome(String core); public void studyAtSchool(String core); }
⑶、創建一個高三學生(G3Student_boy),實現高三學生接口(G3Student),這個高三學生的類就是核心類。
package aop_002; /* * 本例演示的是動態代理 */ //定義一個高三學生的類(目標對象、核心對象、target對象),實現了高三學生的接口。 public class G3Student_boy implements G3Student { //高三學生 的第一個業務流程:在家學習 public void studyAtHome(String core) { //核心的事情是在家學習。 System.out.println(core+"在HOME學習"); } //高三學生 的第二個業務流程:在學校學習 public void studyAtSchool(String core) { //核心的事情是在家學習。 System.out.println(core+"在SCHOOOL學習");
} }
⑷、創建一個高三學生的代理類(G3Student_handler),並且實現了InvocationHandler接口
package aop_002;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; public class G3Student_handler implements InvocationHandler { private Object g3Stu; public G3Student_handler(Object g3Stu) { this.g3Stu = g3Stu; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //調用代理的在核心對象處理核心業務之前的方法 before(); //核心對象的核心方法 Object returnValue = method.invoke(g3Stu, args); //調用代理的在核心對象處理核心業務之後的方法 after(); return returnValue; } private void before(){ //這個是代理(G3Student_handler)准備飯菜的需要做的流程: System.out.println("代理:准備買菜"); System.out.println("代理:准備洗菜"); System.out.println("代理:准備炒菜"); System.out.println("代理:准備煮飯"); System.out.println("-----------------"); } private void after(){ //這個是代理(G3Student_handler)准備補品的需要做的流程: System.out.println("-----------------"); System.out.println("代理 :購買補品"); System.out.println("代理 :熬制部品"); System.out.println("代理 :加入佐料"); System.out.println(); } }
①、其中,和靜態代理不同的是,動態代理的代理類中定義了一個以Object類型的屬性,而靜態代理定義的是具體的G3Student的接口類型的屬性。所以,動態代理這樣定義保證了,這個代理可以帶不同的個核心類如:G3Student_boy、G3Student_girl。
②、這句代碼意思:自動調用傳入的核心類對象(G3Student_boy)的方法,並且傳入參數args,返回一個Object類型的值。具體是調用什麼方法,傳入什麼參數,都不需要我們具體關注,只需寫上這條代碼,並且把返回值返回即可。
⑸、創建一個測試類Test:
package aop_002; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; public class Test { public static void main(String[] args) { G3Student boy = new G3Student_boy(); InvocationHandler handler1 = new G3Student_handler(boy);
G3Student g3boy = (G3Student)Proxy.newProxyInstance(boy.getClass().getClassLoader(), boy.getClass().getInterfaces(),handler1); g3boy.studyAtSchool("小明"); g3boy.studyAtHome("小明"); } }
①、首先,需要創建一個高三學生對象,其次需要創建一個代理類對象,最後使用Proxy創建一個高三學生對象,再調用方法即可。
②、可能有的人會問,為什麼不直接使用第一次創建的高三學生對象直接調用方法呢?如果使用第一次創建的高三學生對象直接調用方法,那麼就沒有代理做的事情顯示,所以應該時候用Proxy創建的高三學生對象,Proxy等於是高三學生對象和代理對象進行一次整合,使它們兩個有機結合在一起,各自做各自的事情。
測試結果:
謝謝浏覽!