您好,登錄后才能下訂單哦!
一、動態代理概念
動態代理分為JDK動態代理和cglib動態代理兩種方式。
jdk動態代理是由Java內部的反射機制來實現的,cglib動態代理底層則是借助asm來實現的。
總的來說,反射機制在生成類的過程中比較高效,而asm在生成類之后的相關執行過程中比較高效(可以通過將asm生成的類進行緩存,這樣解決asm生成類過程低效問題)。
還有一點必須注意:jdk動態代理的應用前提,必須是目標類基于統一的接口。如果沒有上述前提,jdk動態代理不能應用。
由此可以看出,jdk動態代理有一定的局限性,cglib這種第三方類庫實現的動態代理應用更加廣泛,且在效率上更有優勢。
二、JDK動態代理
以下代碼使用代理模式實現一個大小寫字符轉換的功能。
定義接口和實現類:
ISomeService接口:
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; /** * 接口類 * * @author Root */ public interface ISomeService { String doFirst(); void doSecond(); }
SomeServiceImpl實現類:
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; /** * 實現類 * * @author Root */ public class SomeServiceImpl implements ISomeService { @Override public String doFirst() { System.out.println("執行doFirst()..."); String result = "abcde"; return result; } @Override public void doSecond() { System.out.println("執行doSecond()..."); } }
JDK動態代理類:
package com.ietree.basicskill.designpattern.dynamicproxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Main { public static void main(String[] args) { final ISomeService target = new SomeServiceImpl(); // 使用JDK的Proxy動態代理,要求目標類和代理類必須實現相同的接口,因為其底層的執行原理與靜態代理的相同 ISomeService service = (ISomeService) Proxy.newProxyInstance( // 目標類的類加載器 target.getClass().getClassLoader(), // 目標類所實現的所有接口 target.getClass().getInterfaces(), new InvocationHandler() { // proxy:代理對象 // method:目標方法 // args:目標方法的參數列表 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 調用目標方法 Object result = method.invoke(target, args); if (result != null) { result = ((String) result).toUpperCase(); } return result; } }); String result = service.doFirst(); System.out.println(result); service.doSecond(); } }
三、cglib動態代理
Cglib是一個優秀的動態代理框架,它的底層使用ASM在內存中動態的生成被代理類的子類,使用CGLIB即使代理類沒有實現任何接口也可以實現動態代理功能。CGLIB具有簡單易用,它的運行速度要遠遠快于JDK的Proxy動態代理:
CGLIB的核心類:
net.sf.cglib.proxy.Enhancer – 主要的增強類
net.sf.cglib.proxy.MethodInterceptor – 主要的方法攔截類,它是Callback接口的子接口,需要用戶實現
net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method類的代理類,可以方便的實現對源對象方法的調用,如使用:
Object o = methodProxy.invokeSuper(proxy, args);//雖然第一個參數是被代理對象,也不會出現死循環的問題。
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(callback)類型,它經常被基于代理的AOP用來實現攔截(intercept)方法的調用。這個接口只定義了一個方法
public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
第一個參數是代理對像,第二和第三個參數分別是攔截的方法和方法的參數。原來的方法可能通過使用java.lang.reflect.Method對象的一般反射調用,或者使用 net.sf.cglib.proxy.MethodProxy對象調用。net.sf.cglib.proxy.MethodProxy通常被首選使用,因為它更快。
以下程序實現了大小寫轉換的功能:
實現類SomeService:
package com.ietree.basicskill.designpattern.dynamicproxy.cglib; /** * 實現類 * * @author Root */ public class SomeService { public String doFirst() { System.out.println("執行doFirst()..."); String result = "abcde"; return result; } public void doSecond() { System.out.println("執行doSecond()..."); } }
代理類MyCglibFactory:
package com.ietree.basicskill.designpattern.dynamicproxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class MyCglibFactory implements MethodInterceptor { private SomeService target; public MyCglibFactory() { super(); target = new SomeService(); } public SomeService myCglibCreator() { // 創建增強器對象 Enhancer enhancer = new Enhancer(); // 指定目標類,即父類 enhancer.setSuperclass(SomeService.class); // 設置回調接口對象 enhancer.setCallback(this); return (SomeService) enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // 調用目標方法 Object result = method.invoke(target, args); if (result != null) { result = ((String) result).toUpperCase(); } return result; } }
測試:
package com.ietree.basicskill.designpattern.dynamicproxy.cglib; public class Main { public static void main(String[] args) { SomeService service = new MyCglibFactory().myCglibCreator(); String result = service.doFirst(); System.out.println("result = " + result); service.doSecond(); } }
運行結果:
執行doFirst()... result = ABCDE 執行doSecond()...
以上這篇老生常談設計模式之動態代理就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。