深入理解Java Proxy機制

動態代理其實就是java.lang.reflect.Proxy類動態的根據您指定的所有接口生成一個class byte,該class會繼承Proxy類,並實現所有你指定的接口(您在參數中傳入的接口數組);然後再利用您指定的classloader將 class byte加載進系統,最後生成這樣一個類的對象,並初始化該對象的一些值,如invocationHandler,以即所有的接口對應的Method成員。 初始化之後將對象返回給調用的客戶端。這樣客戶端拿到的就是一個實現你所有的接口的Proxy對象。請看實例分析:

一 業務接口類

public interface BusinessProcessor {
    public void processBusiness();
}

二 業務實現類

public class BusinessProcessorImpl implements BusinessProcessor {
    public void processBusiness() {
        System.out.println("processing business.....");
    }
}

三 業務代理類

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

public class BusinessProcessorHandler implements InvocationHandler {

    private Object target = null;

    BusinessProcessorHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("You can do something here before process your business");
        Object result = method.invoke(target, args);
        System.out.println("You can do something here after process your business");
        return result;
    }

}

四 客戶端應用類

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) {
        BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
        BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
        BusinessProcessor bp = (BusinessProcessor) Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
        bp.processBusiness();
    }
}

現在我們看一下打印結果:
You can do something here before process your business
processing business…..
You can do something here after process your business

通過結果我們就能夠很簡單的看出Proxy的作用了,它能夠在你的核心業務方法前後做一些你所想做的輔助工作,如log日誌,安全機制等等。

分析一下上面的類的工作原理

先看看類三吧。 實現了InvocationHandler接口的invoke方法。其實這個類就是最終Proxy調用的固定接口方法。Proxy不管客戶端的業務方法是怎麼實現的。當客戶端調用Proxy時,它只會調用InvocationHandler的invoke接口,所以我們的真正實現的方法就必須在invoke方法中去調用。關係如下:

BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);
bp.processBusiness()-->invocationHandler.invoke()-->bpimpl.processBusiness();

那麼bp到底是怎麼樣一個對象呢。我們改一下main方法看一下就知道了:

public static void main(String[] args) {
  BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
  BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
  BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
  bp.processBusiness();
  System.out.println(bp.getClass().getName());
 }

輸出結果:
You can do something here before process your business
processing business…..
You can do something here after process your business
$Proxy0

bp原來是個$Proxy0這個類的對象。那麼這個類到底是長什麼樣子呢?好的。我們再寫二個方法去把這個類打印出來看個究竟,是什麼三頭六臂呢?我們在main下面寫如下兩個靜態方法。

public static String getModifier(int modifier){
  String result = "";
  switch(modifier){
   case Modifier.PRIVATE:
    result = "private";
   case Modifier.PUBLIC:
    result = "public";
   case Modifier.PROTECTED:
    result = "protected";
   case Modifier.ABSTRACT :
    result = "abstract";
   case Modifier.FINAL :
    result = "final";
   case Modifier.NATIVE :
    result = "native";
   case Modifier.STATIC :
    result = "static";
   case Modifier.SYNCHRONIZED :
    result = "synchronized";
   case Modifier.STRICT  :
    result = "strict";
   case Modifier.TRANSIENT :
    result = "transient";
   case Modifier.VOLATILE :
    result = "volatile";
   case Modifier.INTERFACE :
    result = "interface";
  }
  return result;
 }
public static void printClassDefinition(Class clz){

  String clzModifier = getModifier(clz.getModifiers());
  if(clzModifier!=null && !clzModifier.equals("")){
   clzModifier = clzModifier + " ";
  }
  String superClz = clz.getSuperclass().getName();
  if(superClz!=null && !superClz.equals("")){
   superClz = "extends " + superClz;
  }

  Class[] interfaces = clz.getInterfaces();
  String inters = "";
  for(int i=0; i<interfaces.length; i++){
   if(i==0){
    inters += "implements ";
   }
   inters += interfaces[i].getName();
  }

  System.out.println(clzModifier +clz.getName()+" " + superClz +" " + inters );
  System.out.println("{");

  Field[] fields = clz.getDeclaredFields();
  for(int i=0; i<fields.length; i++){
   String modifier = getModifier(fields[i].getModifiers());
   if(modifier!=null && !modifier.equals("")){
    modifier = modifier + " ";
   }
   String fieldName = fields[i].getName();
   String fieldType = fields[i].getType().getName();
   System.out.println("    "+modifier + fieldType + " "+ fieldName + ";");
  }

  System.out.println();
  Method[] methods = clz.getDeclaredMethods();
  for(int i=0; i<methods.length; i++){
      Method method = methods[i];
      String modifier = getModifier(method.getModifiers());
      if(modifier!=null && !modifier.equals("")){
      modifier = modifier + " ";
  }

  String methodName = method.getName();
  Class returnClz = method.getReturnType();
  String retrunType = returnClz.getName();

  Class[] clzs = method.getParameterTypes();
  String paraList = "(";
  for(int j=0; j<clzs.length; j++){
    paraList += clzs[j].getName();
    if(j != clzs.length -1 ){
      paraList += ", ";
   }
   }
   paraList += ")";

   clzs = method.getExceptionTypes();
   String exceptions = "";
   for(int j=0; j<clzs.length; j++){
    if(j==0){
     exceptions += "throws ";
    }

    exceptions += clzs[j].getName();

    if(j != clzs.length -1 ){
     exceptions += ", ";
    }
   }

   exceptions += ";";

   String methodPrototype = modifier +retrunType+" "+methodName+paraList+exceptions;

   System.out.println("    "+methodPrototype );

  }
  System.out.println("}");
 }

再改寫main方法

public static void main(String[] args) {
  BusinessProcessorImpl bpimpl = new BusinessProcessorImpl();
  BusinessProcessorHandler handler = new BusinessProcessorHandler(bpimpl);
  BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(bpimpl.getClass().getClassLoader(), bpimpl.getClass().getInterfaces(), handler);
  bp.processBusiness();
  System.out.println(bp.getClass().getName());
  Class clz = bp.getClass();
  printClassDefinition(clz);
 }

現在我們再看看輸出結果:
You can do something here before process your business
processing business…..
You can do something here after process your business
Proxy0 Proxy0 extends java.lang.reflect.Proxy implements com.tom.proxy.dynamic.BusinessProcessor
{
java.lang.reflect.Method m4;
java.lang.reflect.Method m2;
java.lang.reflect.Method m0;
java.lang.reflect.Method m3;
java.lang.reflect.Method m1;

void processBusiness();
int hashCode();
boolean equals(java.lang.Object);
java.lang.String toString();

}

很明顯,Proxy.newProxyInstance方法會做如下幾件事:

  1. 根據傳入的第二個參數interfaces動態生成一個類,實現interfaces中的接口,該例中即BusinessProcessor接口的processBusiness方法。並且繼承了Proxy類,重寫了hashcode,toString,equals等三個方法。具體實現可參看 ProxyGenerator.generateProxyClass(…); 該例中生成了$Proxy0類
  2. 通過傳入的第一個參數classloder將剛生成的類加載到jvm中。即將$Proxy0類load
  3. 利用第三個參數,調用$Proxy0的$Proxy0(InvocationHandler)構造函數 創建$Proxy0的對象,並且用interfaces參數遍歷其所有接口的方法,並生成Method對象初始化對象的幾個Method成員變量
  4. 將$Proxy0的實例返回給客戶端。

    現在好了。我們再看客戶端怎麼調就清楚了
    一. 客戶端拿到的是$Proxy0的實例對象,由於$Proxy0繼承了BusinessProcessor,因此轉化爲BusinessProcessor沒任何問題。
    BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(….);
    二. bp.processBusiness(); 實際上調用的是\$Proxy0.processBusiness();那麼\$Proxy0.processBusiness()的實現就是通過InvocationHandler去調用invoke方法啦!

——————————————————————————–

關注微信公衆號“閱享屋”可獲取900G IT教學視頻和JAVA、前端電子書籍
這裏寫圖片描述

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