熟悉动态代理的小伙伴都知道,java的动态代理有两个常用的方式,一个是jdk动态代理,一个是cglib,他们两个在使用上的最大区别就是前者是返回一个接口对象(其实质是Proxy类的子类),后者是返回了被代理类的类对象。
我今天所探讨的,就是修改jdk动态代理的源码使其像cglib一样返回被代理类的类对象。
首先看下Proxy的关键源码:
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 注意这里,就是这里返回了代理类的class对象
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
Proxy类中的newProxyInstance通过getProxyClass0获取到代理类的class对象,通过对代码调用的追踪,发现这个class对象是由ProxyGenerator类生成的。
在ProxyGenerator类中,这个地方需要注意:
ProxyGenerator的generateClassFile方法中会将Proxy.newProxyInstance方法传进来的接口的所有方法都弄成代理方法。这个方法下边还有个地方指定了代理类的父类:
其返回的类示例:
public final class $Proxy0 extends Proxy implements TestInterface {
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 test() 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("MyJDKProxy.TestInterface").getMethod("test");
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());
}
}
}
其中TestInterface :
由此可见,生成的代理类正如我所说,是继承于Proxy类,并将传进来的所有接口的方法弄成代理方法。
基于此,若想将jdk动态代理返回的对象是被代理类的对象,我们主要修改的地方就是ProxyGenerator类,将继承的父类改成被代理类,将被代理类的所有方法设置为代理方法。
这是主要修改的地方,我现在只是提供一个思路,其它还有很多地方需要修改,我就不一一贴出来,有需要可看源码。
先来看下修改后生成的代理类:
public final class $MyProxy0 extends Tester {
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m2;
private static Method m0;
public $MyProxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.invocationHandler.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void doa() throws {
try {
super.invocationHandler.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void test() throws {
try {
super.invocationHandler.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.invocationHandler.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.invocationHandler.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"));
m4 = Class.forName("MyJDKProxy.Tester").getMethod("doa");
m3 = Class.forName("MyJDKProxy.Tester").getMethod("test");
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());
}
}
}
其中 Tester :
测试:
public class Test {
public static void main(String[] as){
System.setProperty("MyJDKProxy.Proxy.ProxyGenerator.saveGeneratedFiles", "true");
System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Tester baseTester = new Tester(null);
TestHandler testHandler = new TestHandler(baseTester);
Tester tester = ProxyUtil.newProxyInstance("invocationHandler", Tester.class, testHandler);
tester.test();
System.out.println();
tester.doa();
System.out.println();
System.out.println();
System.out.println("百:");
long m = System.currentTimeMillis();
for(int i=0;i<100;i++){
TestInterface testInterface = (TestInterface) Proxy.newProxyInstance(Tester.class.getClassLoader(), new Class[]{TestInterface.class}, testHandler);
}
System.out.println("修改前:"+(System.currentTimeMillis()-m));
m=System.currentTimeMillis();
for(int i=0;i<100;i++){
Tester tester1 = ProxyUtil.newProxyInstance("invocationHandler",Tester.class, testHandler);
}
System.out.println("修改后:"+(System.currentTimeMillis()-m));
System.out.println();
System.out.println("万:");
m = System.currentTimeMillis();
for(int i=0;i<10000;i++){
TestInterface testInterface = (TestInterface) Proxy.newProxyInstance(Tester.class.getClassLoader(), new Class[]{TestInterface.class}, testHandler);
}
System.out.println("修改前:"+(System.currentTimeMillis()-m));
m=System.currentTimeMillis();
for(int i=0;i<10000;i++){
Tester tester1 = ProxyUtil.newProxyInstance("invocationHandler",Tester.class, testHandler);
}
System.out.println("修改后:"+(System.currentTimeMillis()-m));
System.out.println();
System.out.println("千万:");
m = System.currentTimeMillis();
for(int i=0;i<10000000;i++){
TestInterface testInterface = (TestInterface) Proxy.newProxyInstance(Tester.class.getClassLoader(), new Class[]{TestInterface.class}, testHandler);
}
System.out.println("修改前:"+(System.currentTimeMillis()-m));
m=System.currentTimeMillis();
for(int i=0;i<10000000;i++){
Tester tester1 = ProxyUtil.newProxyInstance("invocationHandler",Tester.class, testHandler);
}
System.out.println("修改后:"+(System.currentTimeMillis()-m));
}
}
测试结果:
可以看出,在数量少的时候两者相差不大,但是到了千万级明显修改后的更快,这主要是因为修改后少了关于传进来的接口的代码,原来的jdk代理还要对接口进行判断,还要一个个从接口中获取方法,现在只需要从被代理类中获取方法就行了。