動的エージェントProxy
9374 ワード
:
package com.atb.proxy.simple;
public interface ProxyInterface {
public void methodPrint();
}
:
package com.atb.proxy.simple;
public class ProxyImple implements ProxyInterface{
private String aa="sss";
public void methodPrint() {
System.out.println("hi dubbo:"+aa);
}
}
次はエージェントクラスとテストの具体的なコードです.
package com.atb.proxy.simple;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* @author xieronghui
*/
public class DynamicProxy implements InvocationHandler {
//
private Object proxyObject;
/**
* ,
*/
public Object bind(Object proxyObject) {
this.proxyObject = proxyObject;
/**
* loader ;
* interfaces ( ProxyInterface)
* h InvocationHandler(DynamicProxy InvocationHandler)
* public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
*/
return Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(),
proxyObject.getClass().getInterfaces(), this);
}
/**
* $Proxy0 invoke
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(proxyObject, args);
return result;
}
}
テスト対象
package com.atb.proxy.simple;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) throws SecurityException, NoSuchMethodException {
DynamicProxy proxy=new DynamicProxy();
ProxyInterface proxyInter=(ProxyInterface)proxy.bind(new ProxyImple());
//proxyInter.methodPrint();
// proxyInter Proxy , proxyInter
System.out.println(proxyInter instanceof Proxy);
// proxyInter Class $Proxy0, $Proxy0 Proxy, proxyInter
System.out.println("ProxyInterface Class :"+proxyInter.getClass().toString());
System.out.print("ProxyInterface($Proxy0) :");
Field[] field=proxyInter.getClass().getDeclaredFields();
for(Field f:field){
System.out.print(f.getName()+", ");
}
System.out.print("
"+"ProxyInterface--->($Proxy0) :");
Method[] method=proxyInter.getClass().getDeclaredMethods();
for(Method m:method){
System.out.print(m.getName()+", ");
}
System.out.println("
"+"ProxyInterface ($Proxy0) :"+proxyInter.getClass().getSuperclass());
System.out.print("
"+"ProxyInterface ($Proxy0) :");
Class<?>[] interfaces=proxyInter.getClass().getInterfaces();
for(Class<?> i:interfaces){
System.out.print(i.getName()+", ");
}
System.out.println("
"+"# :");
proxyInter.methodPrint();
}
}
結果を返します.
true
ProxyInterface Class :class $Proxy0
ProxyInterface($Proxy0) :m1, m3, m0, m2,
ProxyInterface--->($Proxy0) :equals, toString, hashCode, methodPrint,
ProxyInterface ($Proxy0) :class java.lang.reflect.Proxy
ProxyInterface ($Proxy0) :com.atb.proxy.simple.ProxyInterface,
# :
hi dubbo:sss
ProxyInterfaceのClassクラスは:class$Proxy 0ここから見ることができます
ProxyInterface proxyInter=(ProxyInterface)proxy.bind(new ProxyImple());
返されるClassは$Proxy 0であり、インタフェースがProxyImpleを実装するバイトコードではない.以前はProxyImpleのインスタンスがそのメソッドmethodPrint()を呼び出すことを理解していた.実際にはクラスローダによって$Proxy 0のオブジェクトが動的に構築されており、コンソール印刷で見ることができます.
ProxyInterface----($Proxy 0)では、equals,toString,hashCode,methodPrint、
ProxyInterface($Proxy 0)の親はclass java.lang.reflect.Proxy
$Proxy 0はいつ作られたのでしょうか
public Object bind(Object proxyObject) {
this.proxyObject = proxyObject;
/**
*ここでは、loaderが動的にロードされたエージェントオブジェクトを表す方法を説明します.
*interfacesインタフェース(1つのクラスで複数のインタフェースを実現できますよねここではProxyInterfaceに相当します)
*h InvocationHandler(DynamicProxyオブジェクトがInvocationHandlerを実現)
* public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler h)
*/
return Proxy.newProxyInstance(proxyObject.getClass().getClassLoader(),
proxyObject.getClass().getInterfaces(), this);
}
呼び出したnewProxyInstanceメソッド
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
if (h == null) {
throw new NullPointerException();
}
/*
* Look up or generate the designated proxy class.
*/
Class cl = getProxyClass(loader, interfaces); // $Proxy0
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
Constructor cons = cl.getConstructor(constructorParams);
return (Object) cons.newInstance(new Object[] { h });
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
} catch (IllegalAccessException e) {
throw new InternalError(e.toString());
} catch (InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
throw new InternalError(e.toString());
}
}
getProxyClass()メソッドは長く、直接JDKソースを開いて理解を学ぶことができます
$Proxy0
/** prefix for all proxy class names */
private final static String proxyClassNamePrefix = "$Proxy";
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Verify that the class loader hasn't already
* defined a class with the chosen name.
*/
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
$Proxy 0クラスはinterfacesのインタフェースを実現し、Proxyクラスを継承します.
クラスローダで動的に作成された$Proxy 0
public final class $Proxy0 extends Proxy implements ProxyInterface{
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
m3 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
m2 = Class.forName(" com.atb.proxy.simple.ProxyImple").getMethod("methodPrint",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
} //static
public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}
@Override
public final boolean equals(Object obj) {
try {
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 methodPrint() {
try {
super.h.invoke(this, m2, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m3, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
newProxyInstanceメソッドを続行します
Constructor cons = cl.getConstructor(constructorParams); //
return (Object) cons.newInstance(new Object[] { h }); //
class Proxy{
InvocationHandler h=null;
protected Proxy(InvocationHandler h) {
this.h = h;
}
}
まとめ:実装されたInvocationHandlerインタフェースinvokeはいつ呼び出されるのか
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(proxyObject, args);
return result;
}
$Proxy 0インスタンス--』ProxyInterfaceは、ProxyInterfaceに参照を割り当てます.ProxyInterfaceメソッドを実行する場合、$Proxy 0クラスのmethodPrint()メソッドが呼び出され、さらに親クラスProxyのhのinvoke()メソッドが呼び出される.つまりInvocationHandler.invoke().