動態代理程式分為JDK動態代理程式和cglib動態代理程式兩種方式。
jdk動態代理程式是由Java內部的反射機制來實現的,cglib動態代理底層則是藉助asm來實現的。
總的來說,反射機制在生成類別的過程中比較高效,而asm在生成類別之後的相關執行過程中比較高效(可以透過將asm生成的類別進行緩存,這樣解決asm生成類過程低效率問題)。
還有一點必須注意:jdk動態代理程式的應用前提,必須是目標類別基於統一的介面。如果沒有上述前提,jdk動態代理不能應用。
由此可以看出,jdk動態代理有一定的局限性,cglib這種第三方類別庫實現的動態代理應用更加廣泛,且在效率上更有優勢。
以下程式碼使用代理模式實作一個大小寫字元轉換的功能。
定義介面與實作類別:
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 { @Overridepublic String doFirst() { System.out.println("执行doFirst()..."); String result = "abcde";return result; } @Overridepublic 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:目标方法的参数列表 @Overridepublic 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是一個優秀的動態代理框架,它的底層使用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(); } @Overridepublic 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()...
以上是設計模式之動態代理的詳細內容。更多資訊請關注PHP中文網其他相關文章!