千家信息网

Java如何实现动态代理

发表于:2025-01-16 作者:千家信息网编辑
千家信息网最后更新 2025年01月16日,小编给大家分享一下Java如何实现动态代理,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Java 动态代理准备:maven
千家信息网最后更新 2025年01月16日Java如何实现动态代理

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

Java 动态代理

准备:maven依赖

              cglib        cglib        3.2.5                javassist        javassist        3.12.1.GA              junit      junit      3.8.1      test      
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 执行完成

工程目录下生成代理类文件:

反编译生成的代理类(避免篇幅过大,删除了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文件:

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

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

0