溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java如何實現(xiàn)動態(tài)代理

發(fā)布時間:2021-11-24 10:36:44 來源:億速云 閱讀:145 作者:小新 欄目:編程語言

小編給大家分享一下Java如何實現(xiàn)動態(tài)代理,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

Java 動態(tài)代理

準(zhǔn)備: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方式實現(xiàn)

jdk方式的動態(tài)代理需要通過實現(xiàn)接口來實現(xiàn),因此,先創(chuàng)建一個簡單的接口及實現(xiàn)類:

接口:

package per.ym.proxy.jdk;

public interface BookStore {

    String add(String bookName);

    String delete(String bookName);
}

實現(xiàn)類:

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;
    }

}

創(chuàng)建代理類工廠:

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("調(diào)用方法:" + method.getName());

        String bookName = (String) method.invoke(bookStroe, args);

        System.out.println("方法:" + method.getName() + " 執(zhí)行完成");

        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");
    }

}

測試結(jié)果:

調(diào)用方法:add
增加書籍:thinking in java
方法:add 執(zhí)行完成
調(diào)用方法:delete
刪除書籍:spring in action
方法:delete 執(zhí)行完成

工程目錄下生成代理類文件:
Java如何實現(xiàn)動態(tài)代理

反編譯生成的代理類(避免篇幅過大,刪除了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());
    }
  }
}

從以上得,代理類實現(xiàn)了被代理類的接口(因此使用jdk實現(xiàn)的動態(tài)代理需要被代理類實現(xiàn)接口),并持有傳入的InvocationHandler,當(dāng)調(diào)用代理類的方法時,都會轉(zhuǎn)到InvocationHandler的invoke方法中,并傳入自身,被調(diào)用方法及參數(shù)。

2,Cglib方式實現(xiàn)

Cglib是基于繼承實現(xiàn)的代理,因此,被代理類不需要實現(xiàn),直接使用一個類即可:

被代理類:

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;
    }

}

創(chuàng)建代理類工廠:

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();

        //設(shè)置父類
        enhancer.setSuperclass(bookStore.getClass());

        //回調(diào)方法
        enhancer.setCallback(this);

        //創(chuàng)建代理
        return (BookStore) enhancer.create();
    }

    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("調(diào)用方法:" + method.getName());

        String bookName = (String) methodProxy.invokeSuper(obj, args);

        System.out.println("方法:" + method.getName() + " 執(zhí)行完成");

        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");
    }

}

測試結(jié)果:

CGLIB debugging enabled, writing to 'D:\proxy_test'
調(diào)用方法:add
增加書籍:thinking in java
方法:add 執(zhí)行完成
調(diào)用方法:delete
刪除書籍:spring in action
方法:delete 執(zhí)行完成

指定目錄下生成的代理類class文件:
Java如何實現(xiàn)動態(tài)代理

反編譯生成的代理類(刪除了一些注釋的東西):

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文件,不過能夠看出來生成的代理類是通過繼承被代理類實現(xiàn)的,當(dāng)調(diào)用指定方法時會轉(zhuǎn)到回調(diào)方法中,并傳入自身,被調(diào)用方法,方法參數(shù)和一個MethodProxy,這個MethodProxy還沒仔細(xì)去看是什么,不過猜測應(yīng)該是封裝了被調(diào)用方法相關(guān)的信息,最終也是通過反射調(diào)用被代理對象的相應(yīng)方法,如果猜錯了,不負(fù)責(zé)。

3,Javassist方式實現(xiàn)

javassist可以動態(tài)的生成一個class,關(guān)于它的更多信息,請到這里去: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;
    }

}

創(chuàng)建代理類工廠:

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";

        //創(chuàng)建代理類
        CtClass ctClass = classPool.makeClass(proxyClassName);

        //設(shè)置父類為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();
        //保存方法參數(shù)信息
        StringBuilder paraSb1 = new StringBuilder();
        //保存調(diào)用被代理類方法的參數(shù)信息
        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(\"執(zhí)行方法:" + m.getName() + "\"" + ");")
                   .append(m.getReturnType().getName() + " result = bookStore." + m.getName() + paraSb2 + ";")
                   .append("System.out.println(\"方法:" + m.getName() + " 執(zhí)行完成  \");")
                   .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");
    }

}

測試結(jié)果:

執(zhí)行方法:add
增加書籍:thinking in java
方法:add 執(zhí)行完成  
執(zhí)行方法:delete
刪除書籍:spring in action
方法:delete 執(zhí)行完成

生成的代理類class文件:
Java如何實現(xiàn)動態(tài)代理

反編譯生成的代理類(格式化后的):

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("執(zhí)行方法: add");
    String str = this.bookStore.add(paramString);
    System.out.println("方法: add 執(zhí)行完成  ");
    return str;
  }

  public String delete(String paramString)
  {
    System.out.println("執(zhí)行方法:delete");
    String str = this.bookStore.delete(paramString);
    System.out.println("方法:delete 執(zhí)行完成 ");
    return str;
  }
}

不知道為啥方法參數(shù)名是paramString,而不是我設(shè)置的arg0?

以上是“Java如何實現(xiàn)動態(tài)代理”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI