動態代理其實就是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 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方法會做如下幾件事:
- 根據傳入的第二個參數interfaces動態生成一個類,實現interfaces中的接口,該例中即BusinessProcessor接口的processBusiness方法。並且繼承了Proxy類,重寫了hashcode,toString,equals等三個方法。具體實現可參看 ProxyGenerator.generateProxyClass(…); 該例中生成了$Proxy0類
- 通過傳入的第一個參數classloder將剛生成的類加載到jvm中。即將$Proxy0類load
- 利用第三個參數,調用$Proxy0的$Proxy0(InvocationHandler)構造函數 創建$Proxy0的對象,並且用interfaces參數遍歷其所有接口的方法,並生成Method對象初始化對象的幾個Method成員變量
將$Proxy0的實例返回給客戶端。
現在好了。我們再看客戶端怎麼調就清楚了
一. 客戶端拿到的是$Proxy0的實例對象,由於$Proxy0繼承了BusinessProcessor,因此轉化爲BusinessProcessor沒任何問題。
BusinessProcessor bp = (BusinessProcessor)Proxy.newProxyInstance(….);
二. bp.processBusiness(); 實際上調用的是\$Proxy0.processBusiness();那麼\$Proxy0.processBusiness()的實現就是通過InvocationHandler去調用invoke方法啦!
——————————————————————————–
關注微信公衆號“閱享屋”可獲取900G IT教學視頻和JAVA、前端電子書籍