深入理解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的實例返回給客戶端。

現在好了。我們再看客戶端怎麼調就清楚了。

1,客戶端拿到的是$Proxy0的實例對象,由於$Proxy0繼承了BusinessProcessor,因此轉化爲BusinessProcessor沒任何問題。

BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(....);

2,bp.processBusiness();

實際上調用的是$Proxy0.processBusiness();那麼$Proxy0.processBusiness()的實現就是通過InvocationHandler去調用invoke方法啦!

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