首頁 > Java > java教程 > Java中關於Proxy機制的具體分析

Java中關於Proxy機制的具體分析

黄舟
發布: 2017-10-13 10:10:47
原創
1468 人瀏覽過

這篇文章主要介紹了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方法啦!

總結

以上是Java中關於Proxy機制的具體分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板