一、代理(Proxy)是一種設計模式,提供了對目標對象另外的訪問方式;即經過代理對象訪問目標對象.這樣作的好處是:能夠在目標對象實現的基礎上,加強額外的功能操做,即擴展目標對象的功能.這裏使用到編程中的一個思想:不要隨意去修改別人已經寫好的代碼或者方法,若是需改修改,能夠經過代理的方式來擴展該方法
二、java 的三種代理模式:
2.1)靜態代理:在使用時,須要定義接口或者父類,被代理對象與代理對象一塊兒實現相同的接口或者是繼承相同父類,而後經過調用相同的方法來調用目標對象的方法。
優勢:能夠作到在不修改目標對象的功能前提下,對目標功能擴展.
缺點:由於代理對象須要與目標對象實現同樣的接口,因此會有不少代理類,類太多.同時,一旦接口增長方法,目標對象與代理對象都要維護
示例
//被代理對象與代理對象均要實現的相同的接口java
public interface IUserDao { void save(); }
//目標對象spring
public class UserDao implements IUserDao{ public void save() { System.out.println("----已經保存數據!----"); } }
//代理對象編程
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("提交事務..."); } }
//測試類設計模式
public class TestApp { public static void main(String[] args) { //目標對象 UserDao target = new UserDao(); //代理對象,把目標對象傳給代理對象,創建代理關係 UserDaoProxy proxyObj = new UserDaoProxy(target); proxyObj.save(); } }
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; } }); } }
//測試類(須要使用到代理的代碼)中先創建目標對象和代理對象的聯繫,而後代用代理對象的中同名方法ide
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(); } }
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,那麼就不會被攔截,即不會執行目標對象額外的業務方法.
//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; } }
//測試類性能
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(); } }