Java JDK動態代理


jdk 動態代理的主要三個部分

1. Proxy 類.

2. ClassLoader 

3.InvocationHandler 

 

java中動態代理主要有JDK和CGLIB兩種方式。

區別主要是jdk是代理接口,而cglib是代理類。

jdk的動態代理調用了Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法。

通過該方法生成字節碼,動態的創建了一個代理類,interfaces參數是該動態類所繼承的所有接口,而繼承InvocationHandler 接口的類則是實現在調用代理接口方法前后的具體邏輯,下邊是具體的實現:

復制代碼
public class Test {
  static interface Subject{
    void sayHi();
    void sayHello();
  }
   
  static class SubjectImpl implements Subject{
 
    @Override
    public void sayHi() {
      System.out.println("hi");
    }
 
    @Override
    public void sayHello() {
      System.out.println("hello");
    }
  }
   
  static class ProxyInvocationHandler implements InvocationHandler{
    private Subject target;
    public ProxyInvocationHandler(Subject target) {
      this.target=target;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      System.out.print("say:");
      return method.invoke(target, args);
    }
     
  }
   
  public static void main(String[] args) {
    Subject subject=new SubjectImpl();
    Subject subjectProxy=(Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), new ProxyInvocationHandler(subject));
    subjectProxy.sayHi();
    subjectProxy.sayHello();
     
  }
}
復制代碼

 

復制代碼
/**   
 *    
 * JDK動態代理類   
 *    
 *   
 */    
public class JDKProxy implements InvocationHandler {    
    
    private Object targetObject;//需要代理的目標對象    
    
    public Object newProxy(Object targetObject) {//將目標對象傳入進行代理    
        this.targetObject = targetObject;     
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),    
                targetObject.getClass().getInterfaces(), this);//返回代理對象    
    }    
    
    public Object invoke(Object proxy, Method method, Object[] args)//invoke方法    
            throws Throwable {    
        before();
        Object ret = null;      // 設置方法的返回值    
        ret  = method.invoke(targetObject, args);       //invoke調用需要代理的方法
        after();
        return ret;    
    }    
    
    private void before() {//方法執行前   
        System.out.println("方法執行前 !");    
    }    
    private void after() {//方法執行后    
        System.out.println("方法執行后");    
    }    
}  
復制代碼

 

newProxyInstance方法執行了以下幾種操作。

1.生成一個實現了參數interfaces里所有接口且繼承了Proxy的代理類的字節碼,然后用參數里的classLoader加載這個代理類。

2.使用代理類父類的構造函數 Proxy(InvocationHandler h)來創造一個代理類的實例,將我們自定義的InvocationHandler的子類傳入。

3.返回這個代理類實例。

在main方法中加入System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true"),這樣就會把生成的代理類Class文件保存在本地磁盤上,然后再反編譯可以得到代理類的源碼:

復制代碼
public final class $Proxy0 extends Proxy
 implements Test.Subject
{
 private static Method m4;
 private static Method m1;
 private static Method m3;
 private static Method m0;
 private static Method m2;
  
 static
 {
   try {
     m4 = Class.forName("Test$Subject").getMethod("sayHello", new Class[0]);
     m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
     m3 = Class.forName("Test$Subject").getMethod("sayHi", new Class[0]);
     m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
     m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
 }
 
 public $Proxy0(InvocationHandler paramInvocationHandler)
 {
  super(paramInvocationHandler);
 }
 
 public final void sayHello()
 {
  try
  {
   this.h.invoke(this, m4, null);
   return;
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
    throw new UndeclaredThrowableException(localThrowable);
  }
 }
 
 public final boolean equals(Object paramObject)
 {
  try
  {
   return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
    throw new UndeclaredThrowableException(localThrowable);
  }
 }
 
 public final void sayHi()
 {
  try
  {
   this.h.invoke(this, m3, null);
   return;
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
    throw new UndeclaredThrowableException(localThrowable);
  }
 }
 
 public final int hashCode()
 {
  try
  {
   return ((Integer)this.h.invoke(this, m0, null)).intValue();
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
    throw new UndeclaredThrowableException(localThrowable);
  }
 }
 
 public final String toString()
 {
  try
  {
   return (String)this.h.invoke(this, m2, null);
  }
  catch (RuntimeException localRuntimeException)
  {
   throw localRuntimeException;
  }
  catch (Throwable localThrowable)
  {
    throw new UndeclaredThrowableException(localThrowable);
  }
 }
}
復制代碼

我們可以看到代理類內部實現比較簡單,在調用每個代理類每個方法的時候,都用反射去調newProxyInstanceh方法中傳來的h的invoke方法(也就是我們自定義的InvocationHandler的子類中重寫的invoke方法),用參數傳遞了代理類實例、接口方法、調用參數列表,這樣我們在重寫的invoke方法中就可以實現對所有方法的統一包裝了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM