说下Java动态代理,Spring的AOP就是基于Java的动态代理实现的。动态代理用到的几个类和接口,Proxy提供了一些静态的创建动态代理Class的方法。InvocationHandler接口,代理实现必须实现的接口。
一个简单的例子:
/**
* HelloInterface 接口,定义了一个sayHello的方法
*/
interface HelloInterface{
public void sayHello();
}
/**
* HelloInterface的一个实现类
*/
class HelloImpl implements HelloInterface{
@Override
public void sayHello() {
System.out.println("Hello!");
}
}
/**
* 真正的代理类执行者
*/
class HelloHandler implements InvocationHandler{
HelloInterface helloInterface;
public HelloHandler(HelloInterface helloInterface){
this.helloInterface = helloInterface;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before exec method: "+ method.getName());
method.invoke(helloInterface,args);
System.out.println("after exec method: "+ method.getName());
return null;
}
}
一个简单的测试:
public static void main(String[] args) {
HelloInterface helloInterface = (HelloInterface) Proxy.newProxyInstance(
HelloImpl.class.getClassLoader(),
HelloImpl.class.getInterfaces(),
new HelloHandler( new HelloImpl()));
System.out.println(helloInterface.getClass().getName());
helloInterface.sayHello();
}
输出:
$Proxy0
before exec method: sayHello
Hello!
after exec method: sayHello
Proxy.newProxyInstance
返回的对象名称是$Proxy0
。这个怎么能转成HelloInterface
呢?
分析下Proxy.newProxyInstance
, 首先是3个参数,源码中的,挺简单不翻译了
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
下面就是简化后的代码:
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class>[] intfs = interfaces.clone();
/*
* 在缓存中查找,如果找不到就新建个代理类
*/
Class> cl = getProxyClass0(loader, intfs);
/*
* 调用代理类生成新的实例
*/
final Constructor> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
return cons.newInstance(new Object[]{h});
}
调用方法getProxyClass0 获得Class 对象,这个方法先从proxyClassCache 获得,如果不存在通过ProxyClassFactory 来创建。实际上就是通过生成Class对象的字节数组,最后转成Class对象。
来看具体代码(删除了一些验证的代码)
@Override
public Class> apply(ClassLoader loader, Class>[] interfaces) {
Map, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* 记录非公有的代理接口的包名,并且所有的非公有的代理接口必须在同一个包中。
*/
for (Class> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL;
String name = intf.getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// 如果存在非公有的代理接口包,就用这个,如果都是公有的,就用默认的包com.sun.proxy
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* 此处就是生成$Proxy0的Class的名字
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 生成Class的字节码,通过defineClass0转成Class对象
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
如果细看ProxyGenerator.generateProxyClass会发现$Proxy0 其实实现了代理接口,可以解释了Proxy.newProxyInstance 返回的对象为什么能转成代理接口。如果想看生成的$Proxy0生成的class,可以添加代码System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
来保存$Proxy0.class.
下面来看看生成的代码:
final class $Proxy0 extends Proxy implements HelloInterface {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("test.proxy.HelloInterface").getMethod("sayHello");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
欢迎关注我的公众号: