標籤:nbsp 技術分享 oca 代碼產生 事件處理 功能 ... load 指定
1、代理(Proxy)是一種設計模式,提供了對目標對象另外的訪問方式;即通過代理對象訪問目標對象.這樣做的好處是:可以在目標對象實現的基礎上,增強額外的功能操作,即擴充目標對象的功能.這裡使用到編程中的一個思想:不要隨意去修改別人已經寫好的代碼或者方法,如果需改修改,可以通過代理的方式來擴充該方法
2、java 的三種代理模式:
2.1)靜態代理:在使用時,需要定義介面或者父類,被代理對象與代理對象一起實現相同的介面或者是繼承相同父類,然後通過調用相同的方法來調用目標對象的方法。
優點:可以做到在不修改目標對象的功能前提下,對目標功能擴充.
缺點:因為代理對象需要與目標對象實現一樣的介面,所以會有很多代理類,類太多.同時,一旦介面增加方法,目標對象與代理對象都要維護
樣本
//被代理對象與代理對象均要實現的相同的介面
public interface IUserDao { void save();}View Code
//目標對象
public class UserDao implements IUserDao{ public void save() { System.out.println("----已經儲存資料!----"); }}View Code
//代理對象
public class UserDaoProxy implements IUserDao{ //接收儲存目標對象 private IUserDao target; public UserDaoProxy(IUserDao target){ this.target=target; } public void save() { System.out.println("開始事務..."); target.save(); //執行目標對象的方法 System.out.println("提交事務..."); }}View Code
//測試類別
public class TestApp { public static void main(String[] args) { //目標對象 UserDao target = new UserDao(); //代理對象,把目標對象傳給代理對象,建立代理關係 UserDaoProxy proxyObj = new UserDaoProxy(target); proxyObj.save(); }}View Code
2.2)動態代理
a、動態代理對象不需要實現介面,但是需要指定介面類型.(目標對象一定要實現介面,否則不能用動態代理);
b、代理對象的產生,是利用JDK的API,動態在記憶體中構建代理對象(需要我們指定建立代理對象/目標對象實現的介面的類型);
c、動態代理也叫做:JDK代理,介面代理;
//代理工廠
import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class ProxyFactory { // 維護一個目標對象 private Object target; public ProxyFactory(Object target) { this.target = target; } // 給目標對象組建代理程式對象 public Object getProxyInstance() { //target.getClass().getClassLoader() 指定當前目標對象使用類載入器 //target.getClass().getInterfaces() 目標對象實現的介面的類型 // new InvocationHandler() 事件處理,執行目標對象的方法時,會觸發事件處理器的方法,會把當前執行目標對象的方法作為參數傳入 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("開始事務2"); // 執行目標對象方法 Object returnValue = method.invoke(target, args); System.out.println("提交事務2"); return returnValue; } }); }}View Code
//測試類別(需要使用到代理的代碼)中先建立目標對象和代理對象的聯絡,然後代用代理對象的中同名方法
import daiLi.jingTaiDaiLi.IUserDao;import daiLi.jingTaiDaiLi.UserDao;public class TestApp { public static void main(String[] args) { // 目標對象 IUserDao target = new UserDao(); // 【原始的類型 class cn.itcast.b_dynamic.UserDao】 System.out.println(target.getClass()); // 給目標對象,建立代理對象 IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance(); // class $Proxy0 記憶體中動態產生的代理對象 System.out.println(proxy.getClass()); // 執行方法 【代理對象】 proxy.save(); }}View Code
2.3)Cglib代理
a、Cglib代理上面的靜態代理和動態代理模式都是要求目標對象是實現一個介面的目標對象,但是有時候目標對象只是一個單獨的對象,並沒有實現任何的介面,這個時候就可以使用以目標對象子類的方式類實現代理,這種方法就叫做:Cglib代理 b、Cglib代理,也叫作子類代理,它是在記憶體中構建一個子類對象從而實現對目標對象功能的擴充 Cglib是一個強大的高效能的代碼產生包,它可以在運行期擴充java類與實現java介面.它廣泛的被許多AOP的架構使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截) Cglib包的底層是通過使用一個小而快的位元組碼處理架構ASM來轉換位元組碼並產生新的類.不鼓勵直接使用ASM,因為它要求你必須對JVM內部結構包括class檔案的格式和指令集都很熟悉. 備忘:JDK的動態代理有一個限制,就是使用動態代理的對象必須實現一個或多個介面,如果想代理沒有實現介面的類,就可以使用Cglib實現. c、Cglib子類代理實現方法: 1)需要引入cglib的jar檔案,但是Spring的核心包中已經包括了Cglib功能,所以直接引入Spring-core-3.2.5.jar即可. 2)引入功能包後,就可以在記憶體中動態構建子類 3)代理的類不能為final,否則報錯 4)目標對象的方法如果為final/static,那麼就不會被攔截,即不會執行目標對象額外的業務方法.
View Code
//Cglib代理
import java.lang.reflect.Method;import org.springframework.cglib.proxy.Enhancer;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;public class ProxyFactory implements MethodInterceptor{ //維護目標對象 private Object target; public ProxyFactory(Object target) { this.target = target; } //給目標對象建立一個代理對象 public Object getProxyInstance(){ //1.工具類 Enhancer en = new Enhancer(); //2.設定父類 en.setSuperclass(target.getClass()); //3.設定回呼函數 en.setCallback(this); //4.建立子類(代理對象) return en.create(); } public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("開始事務..."); //執行目標對象的方法 Object returnValue = method.invoke(target, args); System.out.println("提交事務..."); return returnValue; }}View Code
//測試類別
import daiLi.jingTaiDaiLi.UserDao;public class TestApp { public static void main(String args[]) { // 目標對象 UserDao target = new UserDao(); // 代理對象 UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance(); // 執行代理對象的方法 proxy.save(); }}View Code
四、代理模式