您好,登錄后才能下訂單哦!
小編給大家分享一下Java如何實現動態代理,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
準備:maven依賴
<dependencies> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.5</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies>
jdk方式的動態代理需要通過實現接口來實現,因此,先創建一個簡單的接口及實現類:
接口:
package per.ym.proxy.jdk; public interface BookStore { String add(String bookName); String delete(String bookName); }
實現類:
package per.ym.proxy.jdk; public class BookStoreImpl implements BookStore { public String add(String bookName) { System.out.println("增加書籍:" + bookName); return bookName; } public String delete(String bookName) { System.out.println("刪除書籍:" + bookName); return bookName; } }
創建代理類工廠:
package per.ym.proxy.jdk; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class BookStoreJdkProxyFactory implements InvocationHandler{ private BookStore bookStroe; public BookStoreJdkProxyFactory(BookStore bookStore) { this.bookStroe = bookStore; } public BookStore getProxy() { return (BookStore) Proxy.newProxyInstance(bookStroe.getClass().getClassLoader(), bookStroe.getClass().getInterfaces(), this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("調用方法:" + method.getName()); String bookName = (String) method.invoke(bookStroe, args); System.out.println("方法:" + method.getName() + " 執行完成"); return bookName; } }
測試類:
package per.ym.proxy.jdk; public class TestMain { public static void main(String[] args) { //將生成的代理類保存到文件中 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); BookStoreJdkProxyFactory factory = new BookStoreJdkProxyFactory(new BookStoreImpl()); BookStore proxy = factory.getProxy(); proxy.add("thinking in java"); proxy.delete("spring in action"); } }
測試結果:
調用方法:add 增加書籍:thinking in java 方法:add 執行完成 調用方法:delete 刪除書籍:spring in action 方法:delete 執行完成
工程目錄下生成代理類文件:
反編譯生成的代理類(避免篇幅過大,刪除了equals,toString,hashCode方法):
package com.sun.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.lang.reflect.UndeclaredThrowableException; import per.ym.proxy.jdk.BookStore; public final class $Proxy0 extends Proxy implements BookStore { private static Method m1; private static Method m2; private static Method m3; private static Method m4; private static Method m0; public $Proxy0(InvocationHandler paramInvocationHandler) { super(paramInvocationHandler); } public final String add(String paramString) { try { return (String)this.h.invoke(this, m3, new Object[] { paramString }); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } public final String delete(String paramString) { try { return (String)this.h.invoke(this, m4, new Object[] { paramString }); } catch (Error|RuntimeException localError) { throw localError; } catch (Throwable localThrowable) { throw new UndeclaredThrowableException(localThrowable); } } static { try { m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); m3 = Class.forName("per.ym.proxy.jdk.BookStore").getMethod("add", new Class[] { Class.forName("java.lang.String") }); m4 = Class.forName("per.ym.proxy.jdk.BookStore").getMethod("delete", new Class[] { Class.forName("java.lang.String") }); m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); return; } catch (NoSuchMethodException localNoSuchMethodException) { throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); } catch (ClassNotFoundException localClassNotFoundException) { throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); } } }
從以上得,代理類實現了被代理類的接口(因此使用jdk實現的動態代理需要被代理類實現接口),并持有傳入的InvocationHandler,當調用代理類的方法時,都會轉到InvocationHandler的invoke方法中,并傳入自身,被調用方法及參數。
Cglib是基于繼承實現的代理,因此,被代理類不需要實現,直接使用一個類即可:
被代理類:
package per.ym.proxy.cglib; public class BookStore { public String add(String bookName) { System.out.println("增加書籍:" + bookName); return bookName; } public String delete(String bookName) { System.out.println("刪除書籍:" + bookName); return bookName; } }
創建代理類工廠:
package per.ym.proxy.cglib; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class BookStoreCglibProxyFactory implements MethodInterceptor { private BookStore bookStore; public BookStoreCglibProxyFactory(BookStore bookStore) { this.bookStore = bookStore; } public BookStore getProxy() { Enhancer enhancer = new Enhancer(); //設置父類 enhancer.setSuperclass(bookStore.getClass()); //回調方法 enhancer.setCallback(this); //創建代理 return (BookStore) enhancer.create(); } public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println("調用方法:" + method.getName()); String bookName = (String) methodProxy.invokeSuper(obj, args); System.out.println("方法:" + method.getName() + " 執行完成"); return bookName; } }
測試類:
package per.ym.proxy.cglib; import net.sf.cglib.core.DebuggingClassWriter; public class TestMain { public static void main(String[] args) { //將生成的代理類保存到指定目錄下 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\proxy_test"); BookStoreCglibProxyFactory factory = new BookStoreCglibProxyFactory(new BookStore()); BookStore proxy = factory.getProxy(); proxy.add("thinking in java"); proxy.delete("spring in action"); } }
測試結果:
CGLIB debugging enabled, writing to 'D:\proxy_test' 調用方法:add 增加書籍:thinking in java 方法:add 執行完成 調用方法:delete 刪除書籍:spring in action 方法:delete 執行完成
指定目錄下生成的代理類class文件:
反編譯生成的代理類(刪除了一些注釋的東西):
package per.ym.proxy.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.Callback; import net.sf.cglib.proxy.Factory; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class BookStore$$EnhancerByCGLIB$$847c411a extends BookStore implements Factory { private boolean CGLIB$BOUND; public static Object CGLIB$FACTORY_DATA; private static final ThreadLocal CGLIB$THREAD_CALLBACKS; private static final Callback[] CGLIB$STATIC_CALLBACKS; private MethodInterceptor CGLIB$CALLBACK_0; private static Object CGLIB$CALLBACK_FILTER; private static final Method CGLIB$add$0$Method; private static final MethodProxy CGLIB$add$0$Proxy; private static final Object[] CGLIB$emptyArgs; private static final Method CGLIB$delete$1$Method; private static final MethodProxy CGLIB$delete$1$Proxy; private static final Method CGLIB$equals$2$Method; private static final MethodProxy CGLIB$equals$2$Proxy; private static final Method CGLIB$toString$3$Method; private static final MethodProxy CGLIB$toString$3$Proxy; private static final Method CGLIB$hashCode$4$Method; private static final MethodProxy CGLIB$hashCode$4$Proxy; private static final Method CGLIB$clone$5$Method; private static final MethodProxy CGLIB$clone$5$Proxy; final String CGLIB$add$0(String paramString) { return super.add(paramString); } public final String add(String paramString) { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) { tmp4_1; CGLIB$BIND_CALLBACKS(this); } MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0; if (tmp17_14 != null) { return (String)tmp17_14.intercept(this, CGLIB$add$0$Method, new Object[] { paramString }, CGLIB$add$0$Proxy); } return super.add(paramString); } final String CGLIB$delete$1(String paramString) { return super.delete(paramString); } public final String delete(String paramString) { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) { tmp4_1; CGLIB$BIND_CALLBACKS(this); } MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0; if (tmp17_14 != null) { return (String)tmp17_14.intercept(this, CGLIB$delete$1$Method, new Object[] { paramString }, CGLIB$delete$1$Proxy); } return super.delete(paramString); } final boolean CGLIB$equals$2(Object paramObject) { return super.equals(paramObject); } public final boolean equals(Object paramObject) { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) { tmp4_1; CGLIB$BIND_CALLBACKS(this); } MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0; if (tmp17_14 != null) { Object tmp41_36 = tmp17_14.intercept(this, CGLIB$equals$2$Method, new Object[] { paramObject }, CGLIB$equals$2$Proxy); tmp41_36; return tmp41_36 == null ? false : ((Boolean)tmp41_36).booleanValue(); } return super.equals(paramObject); } final String CGLIB$toString$3() { return super.toString(); } public final String toString() { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) { tmp4_1; CGLIB$BIND_CALLBACKS(this); } MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0; if (tmp17_14 != null) { return (String)tmp17_14.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy); } return super.toString(); } final int CGLIB$hashCode$4() { return super.hashCode(); } public final int hashCode() { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) { tmp4_1; CGLIB$BIND_CALLBACKS(this); } MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0; if (tmp17_14 != null) { Object tmp36_31 = tmp17_14.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy); tmp36_31; return tmp36_31 == null ? 0 : ((Number)tmp36_31).intValue(); } return super.hashCode(); } final Object CGLIB$clone$5() throws CloneNotSupportedException { return super.clone(); } protected final Object clone() throws CloneNotSupportedException { MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0; if (tmp4_1 == null) { tmp4_1; CGLIB$BIND_CALLBACKS(this); } MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0; if (tmp17_14 != null) { return tmp17_14.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy); } return super.clone(); } public BookStore$$EnhancerByCGLIB$$847c411a() { CGLIB$BIND_CALLBACKS(this); } public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback) { CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback); } public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback) { CGLIB$STATIC_CALLBACKS = paramArrayOfCallback; } private static final void CGLIB$BIND_CALLBACKS(Object paramObject) { 847c411a local847c411a = (847c411a)paramObject; if (!local847c411a.CGLIB$BOUND) { local847c411a.CGLIB$BOUND = true; Object tmp23_20 = CGLIB$THREAD_CALLBACKS.get(); if (tmp23_20 == null) { tmp23_20; CGLIB$STATIC_CALLBACKS; } local847c411a.CGLIB$CALLBACK_0 = (tmp31_28 == null ? tmp31_28 : (MethodInterceptor)((Callback[])tmp23_20)[0]); } } public Object newInstance(Callback[] paramArrayOfCallback) { CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback); CGLIB$SET_THREAD_CALLBACKS(null); return new 847c411a(); } public Object newInstance(Callback paramCallback) { CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback }); CGLIB$SET_THREAD_CALLBACKS(null); return new 847c411a(); } public Callback getCallback(int paramInt) { CGLIB$BIND_CALLBACKS(this); switch (paramInt) { case 0: break; } return null; } public void setCallback(int paramInt, Callback paramCallback) { switch (paramInt) { case 0: this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramCallback); break; } } public Callback[] getCallbacks() { CGLIB$BIND_CALLBACKS(this); return new Callback[] { this.CGLIB$CALLBACK_0 }; } public void setCallbacks(Callback[] paramArrayOfCallback) { this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramArrayOfCallback[0]); } static {} }
這個看著就有點難受了,而且還生成了其他的class文件,不過能夠看出來生成的代理類是通過繼承被代理類實現的,當調用指定方法時會轉到回調方法中,并傳入自身,被調用方法,方法參數和一個MethodProxy,這個MethodProxy還沒仔細去看是什么,不過猜測應該是封裝了被調用方法相關的信息,最終也是通過反射調用被代理對象的相應方法,如果猜錯了,不負責。
javassist可以動態的生成一個class,關于它的更多信息,請到這里去:https://www.jianshu.com/p/43424242846b
被代理類:
package per.ym.proxy.javassist; public class BookStore { public String add(String bookName) { System.out.println("增加書籍:" + bookName); return bookName; } public String delete(String bookName) { System.out.println("刪除書籍:" + bookName); return bookName; } }
創建代理類工廠:
package per.ym.proxy.javassist; import java.lang.reflect.Method; import javassist.ClassPool; import javassist.CtClass; import javassist.CtField; import javassist.CtNewMethod; public class BookStoreJavassistProxyFactory { public static BookStore getProxy() throws Exception { ClassPool classPool = ClassPool.getDefault(); //代理類名 String proxyClassName = BookStore.class.getName() + "Proxy"; //創建代理類 CtClass ctClass = classPool.makeClass(proxyClassName); //設置父類為BookStore ctClass.setSuperclass(classPool.get(BookStore.class.getName())); //添加屬性bookStore ctClass.addField(CtField.make("private " + BookStore.class.getName() + " bookStore = new " + BookStore.class.getName() + "();", ctClass)); //保存整個方法信息 StringBuilder methodSb = new StringBuilder(); //保存方法參數信息 StringBuilder paraSb1 = new StringBuilder(); //保存調用被代理類方法的參數信息 StringBuilder paraSb2 = new StringBuilder(); //保存異常信息 StringBuilder exceptionSb = new StringBuilder(); Method[] methods = BookStore.class.getDeclaredMethods(); for (Method m : methods) { if (m.getModifiers() == 2) { continue; } methodSb.append(getModifier(m.getModifiers())).append(" ") .append(m.getReturnType().getName()).append(" ") .append(m.getName()); Class<?>[] clazzs = m.getParameterTypes(); paraSb1.append("("); paraSb2.append("("); for (int i=0 ; i< clazzs.length ; i++) { if (paraSb1.length() > 1) { paraSb1.append(",").append(clazzs[i].getName()).append(" ").append("arg" + i); paraSb2.append(",").append("arg" + i); } else { paraSb1.append(clazzs[i].getName()).append(" ").append("arg" + i); paraSb2.append("arg" + i); } } paraSb1.append(")"); paraSb2.append(")"); methodSb.append(paraSb1); clazzs = m.getExceptionTypes(); if (clazzs.length > 0) { methodSb.append(" throws "); for (int i=0; i < clazzs.length; i++) { if (exceptionSb.length() > 0) { exceptionSb.append(",").append(clazzs[i].getName()); } else { exceptionSb.append(clazzs[i].getName()); } } } methodSb.append("{") .append("System.out.println(\"執行方法:" + m.getName() + "\"" + ");") .append(m.getReturnType().getName() + " result = bookStore." + m.getName() + paraSb2 + ";") .append("System.out.println(\"方法:" + m.getName() + " 執行完成 \");") .append("return result;") .append("}"); //添加方法到生成的代理類中 ctClass.addMethod(CtNewMethod.make(methodSb.toString(), ctClass)); methodSb.delete(0, methodSb.length()); paraSb1.delete(0, paraSb1.length()); paraSb2.delete(0, paraSb2.length()); exceptionSb.delete(0, exceptionSb.length()); } //保存生成的class信息到文件中 ctClass.writeFile(); //獲取代理類class對象 Class<BookStore> clazz = ctClass.toClass(); return clazz.newInstance(); } private static String getModifier(int modifier) { switch(modifier) { case 0: return "protected"; case 1: return "public"; case 2: return "private"; case 4: return ""; default: return "public"; } } }
測試類:
package per.ym.proxy.javassist; public class TestMain { public static void main(String[] args) throws Exception { BookStore proxy = BookStoreJavassistProxyFactory.getProxy(); proxy.add("thinking in java"); proxy.delete("spring in action"); } }
測試結果:
執行方法:add 增加書籍:thinking in java 方法:add 執行完成 執行方法:delete 刪除書籍:spring in action 方法:delete 執行完成
生成的代理類class文件:
反編譯生成的代理類(格式化后的):
package per.ym.proxy.javassist; import java.io.PrintStream; public class BookStoreProxy extends BookStore { private BookStore bookStore = new BookStore(); public String add(String paramString) { System.out.println("執行方法: add"); String str = this.bookStore.add(paramString); System.out.println("方法: add 執行完成 "); return str; } public String delete(String paramString) { System.out.println("執行方法:delete"); String str = this.bookStore.delete(paramString); System.out.println("方法:delete 執行完成 "); return str; } }
不知道為啥方法參數名是paramString,而不是我設置的arg0?
以上是“Java如何實現動態代理”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。