温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java如何实现动态代理

发布时间:2021-11-24 10:36:44 来源:亿速云 阅读:197 作者:小新 栏目:编程语言

小编给大家分享一下Java如何实现动态代理,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

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>
1,jdk方式实现

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 执行完成

工程目录下生成代理类文件:
Java如何实现动态代理

反编译生成的代理类(避免篇幅过大,删除了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方法中,并传入自身,被调用方法及参数。

2,Cglib方式实现

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文件:
Java如何实现动态代理

反编译生成的代理类(删除了一些注释的东西):

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还没仔细去看是什么,不过猜测应该是封装了被调用方法相关的信息,最终也是通过反射调用被代理对象的相应方法,如果猜错了,不负责。

3,Javassist方式实现

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文件:
Java如何实现动态代理

反编译生成的代理类(格式化后的):

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如何实现动态代理”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI