java代理模式是一種常見的設計模式。
一、概念:為其他對象提供一種代理以控制對這個對象的訪問。代理對象起到中介作用,可去掉功能服務或增加額外的服務。
二、常見的代理模式有哪些?
- 遠程代理:為不同地理的對象,提供局域網代表對象。
- 虛擬代理:根據需要將資源消耗很大的對象進行延遲,真正需要的時候進行創建。
- 保護代理:控制對一個對象訪問的權限。
- 智能引用代理:提供對目標對象額外的服務。
三、代理模式的兩種實現方式
- 靜態代理:代理和被代理對象在代理之前是確定的,他們都實現相同的接口或者繼承相同的抽象類。
- 動態代理
四、示例
1.通過繼承實現靜態代理
首先,先寫一個接口
public interface Moveable { void move(); }
然后寫接口的實現類
public class Car implements Moveable { @Override public void move() { //實現開車 try { Thread.sleep(new Random().nextInt(1000)); } catch (InterruptedException e) { e.printStackTrace(); } } }
接着是繼承類,在繼承類中,我們實現了父類中的方法,並增加了一些額外的功能,從而實現靜態代理
public class Car2 extends Car{ @Override public void move(){ long starttime = System.currentTimeMillis(); System.out.println("汽車開始行駛.......");
//調用父類中的方法,實現該方法 super.move(); long endtime = System.currentTimeMillis(); System.out.println("汽車結束行駛......"); System.out.println("汽車行駛時間:"+(endtime - starttime)+"毫秒!"); } }
測試方法
public class Test{ public static void main(String[] args) { //使用繼承方式實現 Moveable m = new Car2(); m.move(); } }
2.通過聚合實現靜態代理
編寫聚合類(通過將參數傳遞進來,然后我們使用傳遞進來的參數,調用其方法,實現靜態代理)
public class Car3 implements Moveable{ private Car car; public Car3(Car car) { super(); this.car = car; } @Override public void move() { long starttime = System.currentTimeMillis(); System.out.println("汽車開始行駛.......");
//通過構造方法將car傳進來,然后通過car調用方法 car.move(); long endtime = System.currentTimeMillis(); System.out.println("汽車結束行駛......"); System.out.println("汽車行駛時間:"+(endtime - starttime)+"毫秒!"); } }
測試方法
public class Test { public static void main(String[] args) { //使用聚合方式實現 Car car = new Car(); Moveable m = new Car3(car); m.move(); } }
使用繼承實現靜態代理,會讓我們的代理類無限制的膨脹下去,所以推薦使用聚合實現靜態代理。
五、JDK動態代理
1.定義
在代理類和被代理類之間加上一個事務處理器,將我們需要處理的具體功能放在其中進行處理。
InvocationHandler接口(事務處理器)中僅定義了一個方法public object invoke(Object obj,Method method,Object[] args),在實際使用中,第一個參數obj一般是指代理類,method是被代理的方法,args為該方法的參數數組,這個抽象方法在代理類中動態實現。
Proxy:該類即為動態代理類,通過newProxyInstance方法可以返回代理類的一個實例,返回后的代理類可以當做被代理類使用(可使用被代理類的在接口中聲明過的方法)。
2.實現步驟
- 創建一個實現接口InvocationHandler的類,它必須實現invoke方法,在invoke方法中添加具體的業務邏輯。
- 創建被代理的類和接口。
- 調用Proxy的靜態方法newProxyInstance,動態創建一個代理類。
- 通過代理調用方法。
3.示例
public class TimeHandler implements InvocationHandler{ private Object target; public TimeHandler(Object target) { super(); this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { long starttime = System.currentTimeMillis(); System.out.println("汽車開始行駛......."); method.invoke(target); long endtime = System.currentTimeMillis(); System.out.println("汽車結束行駛......"); System.out.println("汽車行駛時間:"+(endtime - starttime)+"毫秒!"); return null; } }
public class TestProxy { 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動態代理
示例:
首先需引入cglib的jar包
對應的實體類
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; } }
public class Test { public static void main(String[] args) { //創建返回代理類對象 CglibProxy proxy = new CglibProxy(); //為trian返回代理類對象 Train t = (Train) proxy.getProxy(Train.class); //調用方法 t.move(); } }
JDK動態代理和CGLIB動態代理的區別
JDK動態代理:
- 只能代理實現了接口的類。
- 沒有實現接口的類不能實現JDK的動態代理。
CGLIB動態代理:
- 針對類來實現代理。
- 對指定目標類產生一個子類,通過方法攔截技術攔截所有父類方法的調用。
動態代理的典型應用:spring AOP:同時用到了JDK動態代理和CGLIB動態代理。