詳解JAVA設計模式之代理模式
什麼是設計模式(Design Pattern)?
設計模式是一套被反覆使用,多數人知曉的,經過分類編目的,程式碼設計經驗的總結。
代理模式的定義?
代理模式就是為其他物件提供一種代理,以控制對這個物件的訪問。
代理物件起到中介作用,可去掉功能服務或增加額外的服務。
代理物件和目標物件的關係?
代理物件:增強後的物件
目標物件:被增強的物件
他們不是絕對的,會根據情況發生變化。
代理模式的兩種實現方式?
1.靜態代理:代理和被代理物件在代理之前是確定的,它們都實現相同的介面或者繼承相同的抽象類。
2.動態代理:JDK通過介面反射得到位元組碼,然後把位元組碼轉換成class(通過native方法)
靜態代理實現的兩種方式?
使用繼承方式實現和使用聚合方式實現。
繼承:代理物件繼承目標物件,重寫需要增強的方法。缺點:代理類過多,產生類爆炸。
聚合:目標物件和代理物件實現同一個介面,代理物件當中要包含目標物件。
動態代理的實現方式?
Java動態代理類位於java.lang.reflect包下,一般主要涉及到以下兩個類:
1.Interface InvocationHandler : 該介面中僅定義了一個方法,public Object invoke(Object obj,Method method,Object[] args),在實際使用時,第一個引數obj一般是指代理類,method是被代理的方法,args是該方法的引數陣列,這個抽象方法在代理類中動態實現。
2.Proxy 該類即為動態代理類,static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理類的一個例項,返回後的代理類可以當做被代理類使用(可使用被代理類在介面中宣告過的方法)
所謂的動態代理是這樣一種class:它是在執行時生成的class,該class需要實現一組interface,使用動態代理類時,必須實現InvocationHandler介面。
JDK動態代理和CGLIB動態代理的區別?
1.JDK動態代理只能代理實現了介面的類,沒有實現介面的類不能實現JDK的動態代理。
2.CGLIB動態代理針對類來實現代理的,對指定目標類產生一個子類,通過方法攔截技術攔截所有的父類方法的呼叫。
動態代理實現的思路:
1.宣告一段原始碼(動態產生代理)
2.編譯原始碼(JDK Compiler API ),產生新的類(代理類)
3.將這個類load到記憶體中,產生一個新的物件(代理物件)
4.return 代理物件。
使用靜態代理的例子:
1.首先建立業務邏輯介面
/** * 介面 * @author Administrator * */ public interface Moveable { /** * * 介面中的方法 * @Description: TODO * @returnType: void */ void move(); }
2.建立實現類,實現介面中的方法
/** * 實現類 * @author Administrator * */ public class Car implements Moveable { @Override public void move() { //實現開車 try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽車行駛中..."); } catch (InterruptedException e) { e.printStackTrace(); } } }
3.使用繼承方式實現對實現類的代理
/** * 使用繼承方式實現代理 * @author Administrator * */ public class Car2 extends Car { /* (non-Javadoc) * @see com.wk.design.proxy.Car#move() * 直接呼叫父類的move方法,這樣就形成了一個Car2對Car的代理 */ @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽車開始行駛..."); //使用繼承的方式呼叫父類的move()方法 super.move(); long endTime = System.currentTimeMillis(); System.out.println("汽車行駛結束... 汽車行駛時間:"+(endTime-startTime)+"毫秒。"); } }
4.建立測試類
/** * 測試類 * @author Administrator * */ public class Test { public static void main(String[] args) { // Car car = new Car(); // car.move(); //使用繼承方式實現代理 Moveable car2 = new Car2(); car2.move(); //使用聚合方式實現代理 // Car car = new Car(); // Moveable car3 = new Car3(car); // car3.move(); } }
5.使用聚合方式實現對實現類的代理
日誌代理類
/** * * 日誌代理類 * @author Administrator * */ public class CarLogProxy implements Moveable { /** * 使用介面宣告代理類 */ private Moveable m; /** * 通過構造方法的引數傳入代理類 * @param m */ public CarLogProxy(Moveable m) { super(); this.m = m; } @Override public void move() { System.out.println("日誌開始"); //呼叫代理類的方法 m.move(); System.out.println("日誌結束"); } }
時間代理類
/** * 時間代理類 * @author Administrator * */ public class CarTimeProxy implements Moveable { /** * 使用介面宣告代理類 */ private Moveable m; /** * 通過構造方法的引數傳入代理類 * @param m */ public CarTimeProxy(Moveable m) { super(); this.m = m; } @Override public void move() { long startTime = System.currentTimeMillis(); System.out.println("汽車開始行駛..."); //呼叫代理類的方法 m.move(); long endTime = System.currentTimeMillis(); System.out.println("汽車行駛結束... 汽車行駛時間:"+(endTime-startTime)+"毫秒。"); } }
6.建立聚合方式測試類
/** * 聚合代理測試類 * @author Administrator * */ public class TestJuHeProxy { public static void main(String[] args) { Car car = new Car(); //先記錄日誌,再記錄時間 // CarTimeProxy ctp = new CarTimeProxy(car); // CarLogProxy clp = new CarLogProxy(ctp); // clp.move(); //先記錄時間,再記錄日誌 CarLogProxy clp = new CarLogProxy(car); CarTimeProxy ctp = new CarTimeProxy(clp); ctp.move(); } }
使用JDK動態代理實現的例子:
1.建立一個實現介面InvocationHandler的類,它必須實現invoke()方法。
2.建立被代理類及介面
3.呼叫Proxy的靜態方法,建立一個代理類
4.通過代理呼叫方法
/** * 使用jdk的動態代理 * @author Administrator * */ public class TimeHandler implements InvocationHandler { /** * 被代理物件 */ private Object target; public TimeHandler(Object target) { super(); this.target = target; } /** * 引數: * proxy : 被代理物件 * method : 被代理物件的方法 * args : 方法的引數 * 返回值: * Object 方法的返回值 */ @Override public Object invoke(Object proxy,Object[] args) throws Throwable { //在執行被代理物件的方法之前執行自己的邏輯 long startTime = System.currentTimeMillis(); System.out.println("汽車開始行駛..."); //執行被代理物件的方法 method.invoke(target); //在執行被代理物件的方法之後執行自己的邏輯 long endTime = System.currentTimeMillis(); System.out.println("汽車行駛結束... 汽車行駛時間:"+(endTime-startTime)+"毫秒。"); return null; } }
/** * JDK動態代理測試類 * @author Administrator * */ public class JdkProxyTest { public static void main(String[] args) { Car car = new Car(); InvocationHandler h = new TimeHandler(car); Class<?> cls = car.getClass(); /** * 引數: * loader : 類載入器 * interfaces : 實現介面 * h InvocationHandler */ Moveable m= (Moveable)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(),h); //執行被代理類的方法 m.move(); } }
使用CGLIB動態代理實現的例子:
1.建立代理類,實現MethodInterceptor介面
2.使用Enhancer類建立代理方法
3.建立被代理類,並編寫代理方法
4.通過代理呼叫方法
/** * 使用cglib動態代理 * @author Administrator * */ public class Train { public void move(){ System.out.println("火車行駛中。。。"); } }
public class CglibProxy implements MethodInterceptor { private Enhancer enhancer = new Enhancer(); //建立代理類方法 public Object getProxy(Class clazz){ //設定建立子類的類 enhancer.setSuperclass(clazz); //回撥函式 enhancer.setCallback(this); //建立並返回子類的例項 return enhancer.create(); } /** * 作用:攔截所有目標類方法的呼叫 * obj : 目標類的例項 * m : 目標方法的反射物件 * args : 方法的引數 * proxy : 代理類的例項 */ @Override public Object intercept(Object obj,Method m,Object[] args,MethodProxy proxy) throws Throwable { //在呼叫方法時實現自己的業務邏輯 System.out.println("日誌開始..."); //代理類呼叫父類的方法 proxy.invokeSuper(obj,args); //呼叫方法之後實現自己的業務邏輯 System.out.println("日誌結束..."); return null; } }
/** * 使用cglib動態代理的測試類 * @author Administrator * */ public class CglibProxyTest { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); //傳入要代理的類 Train t = (Train)proxy.getProxy(Train.class); //執行方法 t.move(); } }
以上就是詳解JAVA設計模式之代理模式的詳細內容,更多關於JAVA 代理模式的資料請關注我們其它相關文章!