1. 程式人生 > 其它 >動態代理與AOP原理

動態代理與AOP原理

靜態代理

要知道什麼是動態代理,首先要知道什麼是靜態代理?

package DynamicProxy;

/**
 *  頂層介面
 */
interface ClothFactory{
  void produce(String product);
}
/**
 * 被代理類:相當於品牌、企業
 *    因為在建立代理類物件的時候需要建立被代理類的物件,所以兩個類都需要實現ClothFactory介面
 */
class NikeClothFactory implements ClothFactory{
  @Override
  public void produce(String product) {
    System.out.println("Nike"+product);
  }
}
/**
 * 代理類:相當於生產衣服的工廠代理商販
 */
class ProxyClothFactory implements ClothFactory{
  // 用被代理類物件進行例項化
  private ClothFactory factory;

  // 構造器:表示代理的是誰
  public ProxyClothFactory(ClothFactory factory) {
    this.factory = factory;
  }
  // 代理類具體要做的事情:看似是被代理類做的事情,實際上是代理類做的事情
  @Override
  public void produce(String product) {
    System.out.println("代理工廠做一些準備工作...");
    factory.produce("生產一批"+product);
    System.out.println("代理工廠做一些後續的收尾工作..");
  }
}

/**
 * 測試類:
 */
public class staticProxy {
  public static void main(String[] args) {
    // 建立被代理類的物件
    NikeClothFactory ncf = new NikeClothFactory();
    // 建立代理類的物件
    ProxyClothFactory pcf = new ProxyClothFactory(ncf);

    pcf.produce("Air Force1");
  }
}

動態代理

動態代理demo

package DynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 頂層介面:
 * 動態代理測試:
 *    不論是動態代理還是靜態代理都需要有介面和被代理類
 *    區別就是:代理類物件是在什麼時候建立的,建立了幾個。
 */
interface Human{
  String getBelif();
  void eat(String food);
}

/**
 *  被代理類:實現頂層介面抽象方法
 */
class SuperMan implements Human{
  @Override
  public String getBelif() {
    return "I believe I can fly~";
  }

  @Override
  public void eat(String food) {
    System.out.println("我喜歡吃"+food);
  }
}

/**
 *  如何建立動態代理類?
 *  要想實現動態代理需要解決下面2個問題:
 *      問題1. 如何根據已經載入到記憶體中的被代理類,動態的建立一個代理類及其物件
 *      問題2. 當通過代理類的物件呼叫方法時,如何動態的去呼叫被代理類中的同名方法
 */
class ProxyFactory{
  // 問題1:呼叫此方法,返回一個代理類的物件,這樣就動態的建立了一個代理類的物件。其中obj表示被代理類的物件,表示代理誰
  public static Object getProxyInstance(Object obj){
    /**
     * 引數1:獲取被代理類的載入器
     * 引數2:獲取被代理類實現了哪些介面
     * 引數3:獲取代理類呼叫了哪些被代理類的方法,需要自己寫介面實現類,去實現InvocationHandler介面,並且重寫invoke方法的時候,如果代理類物件呼叫某方法a時,會自動的呼叫invoke方法
     */
    MyInvocationhandler handler = new MyInvocationhandler();
    // 呼叫bind方法,指明具體呼叫了哪個被代理類.因為obj就是被代理類的物件
    handler.bind(obj);
    return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
  }
}

/**
 * 如何建立動態代理類?
 *
 */
class MyInvocationhandler implements InvocationHandler{
  // 宣告被代理類的物件,但是不能確定是哪個物件,所以寫Object型別
  private Object obj;
  // 對被代理類的物件進行賦值
  public void bind(Object obj){
    this.obj = obj;
  }
  /**
   *  invoke裡面寫被代理類的方法的邏輯,但是被代理物件還沒有需要在上面提前建立
   *    引數1:就是上面ProxyFactory中方法返回的物件
   *    引數2:代理類物件呼叫的方法,此方法也就作為了被代理類物件要呼叫的方法
   *    引數3:呼叫方法傳遞的實參
   */
  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 傳入被代理類物件和引數,呼叫的是被代理類的哪個方法
    Object invoke = method.invoke(obj, args);
    // 返回的invoke實際上就是被代理類物件的返回值
    return invoke;
  }
}
/**
 * 測試:
 *    1.建立被代理類物件
 *    2.動態的建立代理類的物件,傳入被代理類物件
 *    3.有了代理類物件就可以通過代理類物件invoke方法呼叫被代理類物件的方法和屬性
 */
public class DynamicProxy {
  public static void main(String[] args) {
    // 1.建立被代理類物件
    SuperMan man = new SuperMan();
    // 2.動態的建立代理類的物件:需要用頂層介面Human接收,因為如果不強轉為Human就不能呼叫被代理類重寫的抽象方法,並且她們都實現了Human介面

    // 用Object接收是不對的
    //Object proxyInstance = ProxyFactory.getProxyInstance(man);
    Human proxyInstance1 = (Human)ProxyFactory.getProxyInstance(man);
    String belief = proxyInstance1.getBelif();
    System.out.println(belief);
    proxyInstance1.eat("重慶小火鍋");

    System.out.println("****************把靜態代理類的例子也改成動態代理實現:****************");
    //1.建立被代理類物件
    NikeClothFactory nike = new NikeClothFactory();
    // 2.動態的建立代理類的物件
    ClothFactory proxyInstance2 = (ClothFactory)ProxyFactory.getProxyInstance(nike);
    proxyInstance2.produce("Nike daybreak");
  }
}