以下的內容部分參考了網路上的內容,在此對原作者表示感謝!
Java中動態代理程式的實現,關鍵是這兩個東西:Proxy、InvocationHandler,以下從InvocationHandler介面中的invoke方法入手,簡單說明Java如何實現動態代理的。
首先,invoke方法的完整形式如下:
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable#112 {
## return
null;
Java程式碼
A method invocation on a proxy instance through one of its proxy interfaces will be dispatchedo proxy instance, a java.lang.reflect.Method object identifying the method that was invoked, and an array of type Object containing the . 因此可以知道以上的猜測是正確的,同時也知道,proxy參數傳遞的即是代理類別的實例。 為了方便說明,這裡寫一個簡單的範例來實作動態代理。
#Java代碼
Java代碼
//抽象角色(動態代理只能代理介面)
public void request();
}
//真實角色:實作了Subject的request()方法
public #class RealSubject implements Subject{
public void request(){
System.out.println("From real subject.");
}
}
Java程式碼
//實作了InvocationHandler
class DynamicSubject
#implements##{
private Object obj;//這是動態代理的好處,被封裝的物件是Object類型,接受任意型別的物件
public DynamicSubject ()
;
}
##
//這個方法不是我們所顯示的去呼叫# System.out.println("before cal# +#1method); ## method.invoke(obj, args); //----->這一步詳看下一篇文章,java 以反射機制呼叫某個類別的方法,看完你會了解的。
System.out.println(
//用戶端:產生代理實例,並且呼叫了request()方法
public
public static #void main(String[] args) throws Throwable{
## Subject rs=new RealSubject();//這裡指定被代理類
InvocationHandler ds=new DynamicSubject(rs);
## //以下為一次產生代理程式
## Subject subject=(Subject) Proxy.newProxyInstance(
## ds);//這裡可以透過運作結果證明subject是Proxy的一個實例,這個實例實現了Subject介面
## System.out.println(subject instanceof Proxy);
//這裡可以看出subject的Class類別是$Proxy0,這個$Proxy0類別繼承了Proxy,實作了Subject介面
"subject的Class類別是:"+subject.getClass().toString());
for(Field f:field){
"subject中的方法有:");
## Method[] method=subject.getClass().getDeclaredMethods();
### "); ############### } ######################## ##"\n"+###"subject的父類別是:"+subject.getClass().getSuperclass()); ############################# ########## System.out.print(###"\n"+###"subject實作的介面是:"); ############################################################################################ ################# Class>[] interfaces=subject.getClass().getInterfaces(); ############## ########## ###for(Class> i:interfaces){ ################ )+###", "); ########
}
System.out. "運作結果為:");
#before calling public abstract void ***.Subject.request() From real subject.
fter void ***.Subject.request()
PS:這個結果的訊息非常重要,至少對我來說。因為我在動態代理犯暈的根源就在於將上面的subject.request()理解錯了,至少是被表面所迷惑,沒有發現這個subject和Proxy之間的聯繫,一度糾結於最後調用的這個request( )是怎麼跟invoke()聯絡上的,而invoke又是怎麼知道request存在的。其實上面的true和class $Proxy0就能解決很多的疑問,再加上下面將要說的$Proxy0的源碼,完全可以解決動態代理的疑惑了。
public static Object newProxyInstance(ClassLoader loader,
## ,
IncallingHandler h)
#拋出IllegalArgumentException
#{
if (h == null) {
new空指標異常();
/*
Proxy
建構函式cons = cl.getConstructor(constructorParams);
new Object[] { h });
} catch (NoSuchMethodException e) {
# ##新的內部錯誤(e.toString());
}
catch (IllegalAccessException e) {# ##新的內部錯誤(e.toString());
} catch (InstantiationException e) {
}
catch (InitationTargetException e) {## ##新的內部錯誤(e.toString());
}
}##
Proxy.newProxyInstance(ClassLoader loader, Class>Class>Class> ;[] interfaces, InvocationHandler h)做了以下幾件事.
(1)根據參數loader和interfaces調用方法getProxyClass(loader, interfaces)創建代理類$Proxy0.$Profaces調用類實現了interfaces的接口,並並繼承了Proxy類別.
(2)實例化$Proxy0並在建構方法中把DynamicSubject傳過去,接著$Proxy0呼叫父類別Proxy的建構器,為h賦值,如下:
#class Proxy{
# InvocationHandler h=null;
protected Proxy(InvocationHandler h) {
= h;
#'
來看看這個繼承了Proxy的$Proxy0的原始碼:
public final class $Proxy0 extends Proxy implements Subject {
#11 # private
static 方法m1;private
static 方法 m0;private static 方法 m3;
private static 方法 m2; ##########靜止的{###### # try {
Fnew Class[] { Class.forName("java.lang.Object"#new Class[] { Class.forName("java.lang.Object"#new Class);
m0 = Class.forName(
"java.lang.Object").getMethod(# 地
m3 = Class.forName(
"***.RealSubject").getMethod(0]);
"toString",
new Class[
}
catch (NoSuchMethodException nosuchmethnew NoSuchMethodError(nosuchmethodException.getMessage());
新的 NoClassDefFoundError(classnotfoundException.getMessage()); ###########//靜止的#### #
## public $Proxy0(InitationHandler incallinghandler) { ##
}
################## ###@Override ######## ###@Override ########## ###public ###final ###boolean equals(Object obj) { ############### ##試{ ######return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void request() {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
The Proxy0 instance is cast to Subject and the reference is assigned to subject. When the subject.request() method is executed, the request() method in the $Proxy0 class is called, and then the invoke() method of h in the parent class Proxy is called. That is, InvocationHandler.invoke().
PS: 1. One thing that needs to be explained is that the getProxyClass method in the Proxy class returns the Proxy Class class. The reason why I explain this is because I made a low-level mistake at the beginning, thinking that what was returned was the "Class of the proxied class" - -! It is recommended to take a look at the source code of getProxyClass, it is very long =. =
2. It can be seen from the source code of $Proxy0 that the dynamic proxy class not only proxies the methods in the explicitly defined interface, but also proxies the inherited equals() in the java root class Object. , hashcode(), toString(), and only these three methods.
Q: So far, there is still a question. The first parameter in the invoke method is an instance of Proxy (to be precise, the instance of $Proxy0 is ultimately used), but what? What to use? In other words, how does the program show its effect?
A: From my current level, this proxy parameter has no effect. In the entire dynamic proxy mechanism, the proxy parameter of the invoke method in InvocationHandler is not used. The parameter passed in is actually an instance of the proxy class. I think it may be to allow programmers to use reflection in the invoke method to obtain some information about the proxy class.
#
以上是Java中動態代理的實作教程的詳細內容。更多資訊請關注PHP中文網其他相關文章!