java使用反射生成JDK動態代理

一、基本簡介
在java的java.lang.reflect包下提供了一個Proxy類和InvocationHandler接口,通過使用這個類和接口可以生成JDK動態代理類或動態代理對象。

Proxy類提供了兩個方法:

  1. static Class< ? > getProxyClass( ClassLoader loader,Class< ? > … interfaces) :
    創建一個動態代理類所對應的Class對象,該代理類將實現interfaces所指定的多個接口。
    第一個參數指定生成動態代理類的類加載器。

  2. static Object newProxyInstance( ClassLoader loader,Class< ? >[] interfaces,InvocationHandler h):
    直接創建一個動態代理對象,該代理對象的實現類實現了Interfaces指定的系列接口,執行代理對象的每個方法都會被替換成InvocationHandler對象的invoke方法。

實際上,即使採用第一種方法生成動態代理類之後,如果程序需要通過該代理類來創建代理對象,還是需要傳入一個InvocationHandler實例。

代碼示例:

 try {
      //創建一個InvocationHandler對象
      InvocationHandler invocationHandler = new MyInvocationHandler();
      //使用Proxy生成一個動態代理類proxyClass
      Class proxyClass= Proxy.getProxyClass(Foo.class.getClassLoader(),Foo.class);
      //獲取一個proxyClass類帶InvocationHandler參數的構造器
      Constructor constructor = proxyClass.getConstructor(InvocationHandler.class);
      //調用constructor的newInstance方法生成動態代理實例
      Foo foo = (Foo) constructor.newInstance(invocationHandler);
    } catch (Exception e) {
      e.printStackTrace();
    }

以上的代碼可以簡化爲下面的代碼

InvocationHandler invocationHandler = new MyInvocationHandler();
    Foo foo= (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),new Class[]{Foo.class},invocationHandler);

二、實踐操作

public interface Person {
  void sleep();
}

public class Man implements Person {
  @Override public void sleep() {
    System.out.println("開始睡覺了");
  }
}

public class LogUtil {
  public void filter1(){
    System.out.println("在代理對象的方法執行之前,進行攔截做點什麼");
  }
  public void filter2(){
    System.out.println("在代理對象的方法執行之後,進行攔截做點什麼");
  }
}

生成代理對象

public class MyProxyFactory {
  public static  Object getProxy(Object target){
    MyInvocationHandler handler = new MyInvocationHandler();
    handler.setTarget(target);
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),handler);
  }
}
public class MyInvocationHandler implements InvocationHandler {
  //需要被代理的對象
  private Object target;
  public void setTarget(Object target){
    this.target=target;
  }
  //1.proxy代表動態代理的對象
  //2.method代表正在執行的方法
  //3.args代表調用目標方法時傳入的實參
  @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    LogUtil log = new LogUtil();
    log.filter1();
    //通過反射執行動態代理對象的所有方法
    Object obj=method.invoke(target,args);
    log.filter2();
    return obj;
  }
}
 public static void main(String[] args){
    Person target = new Man();
    Person man= (Person) MyProxyFactory.getProxy(target);
    man.sleep();
  }

運行結果:
這裏寫圖片描述

三、總結
一般普通編程無需用到動態代理,但在編寫框架或底層代碼時,它的作用就非常大了。還有就是使用動態代理可以非常靈活的實現解耦。

參考《瘋狂java講義》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章