动态代理和静态代理的区别,顾名思义,静态代理需要你提前写好代理类,代理类存在于源码之中;动态代理的代理类在运行期间动态生成,这就涉及到在运行期生成class的操作。
public interface Husband {
void careFamily();
}
public interface Father {
void teachChild();
}
Man man = new Man();
Object o = Proxy.newProxyInstance(Man.class.getClassLoader(), new Class[]{Husband.class, Father.class}, new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
return method.invoke(man, objects);
}
});
((Husband)o).careFamily();
((Father)o).teachChild();
简单看下源码
可以看到,返回值是getProxyClass0方法得到的Class后,通过反射创建了这个Class的对象,那么getProxyClass0做了什么(省略了部分代码)?
public static Object newProxyInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2) throws IllegalArgumentException {
Class var5 = getProxyClass0(var0, var3);
final Constructor var6 = var5.getConstructor(constructorParams);
return var6.newInstance(var2);
}
可以看到是从一个WeakCache<ClassLoader, Class[], Class>取出来的,说明已经生成好了,生成的时机我们先不去考虑(省略了部分代码)。
private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache(new Proxy.KeyFactory(), new Proxy.ProxyClassFactory());
private static Class<?> getProxyClass0(ClassLoader var0, Class... var1) {
return (Class)proxyClassCache.get(var0, var1);
}
关键就是在ProxyClassFactory类中。
Proxy.newProxyInstance 会创建一个Class,与静态代理不同,这个Class不是由具体的.java源文件编译而来,即没有真正的文件,只是在内存中按照Class格式生成了一个Class。
在Proxy中有一个静态内部类:ProxyClassFactory,在他的apply方法中可以看到这样一行代码。
String var23 = var16 + "$Proxy" + var19;
//第一参数表示类名,是拼装后的,第二个表示 Class<?>[] var1,代理接口数组
byte[] var22 = ProxyGenerator.generateProxyClass(var23, var2, var17);
通过这个方法会在内存中生成一个类的字节码数组,然后
Proxy.defineClass0(var1, var23, var22, 0, var22.length);
定义出这个类,内存中就有这个类了
模拟生成这个类
我们按照这种方式,将生成类写入文件可以看到类长什么样子
String name = Husband.class.getName() + "$Proxy0";
//生成代理指定接口的Class数据
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Husband.class});
FileOutputStream fos = new FileOutputStream("lib/" + name + ".class");
fos.write(bytes);
fos.close();
生成的类如下,可以看到,这个类继承自Proxy,实现了我们需要代理的接口,继承自Proxy,从前边的分析我们可以知道,Proxy.newProxyInstance返回的就是这个类的对象,所以他可以强转成我们的代理接口,因为实现自这个接口
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.enjoy.lib;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class Husband$Proxy0 extends Proxy implements Husband {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
//可以看到静态代码块中生成了四个方法,其中有三个equals toString hashCode是每个类自带的(Object)
//careFamily是我们接口中提供的方法
//类一生成就通过反射获取到了几个关键方法的method
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.enjoy.lib.Husband").getMethod("careFamily");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
public Husband$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 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 void careFamily() throws {
try {
//当外界调用careFamilly方法的时候,会执行到这里,h就是传入的InvocationHandler
//m3就是静态代码块中获取到的careFamily方法(来自接口),因为我们方法没有传参数,所以为null
super.h.invoke(this, m3, (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);
}
}
}
所以看到这里我们大概可以知道动态代理的原理了,动态代理通过传入的代理接口在内存中生成一个代理类的Class,这个代理类实现了我们传入接口的方法,如此一来,外部在拿到代理对象的时候就可以强转成对应的接口,调用相应的方法,调用方法后会执行代理对象中对应的方法,然后通过InvocationHandler的invoke方法将对应接口的对应方法的method和参数回调出来,然后再次使用反射,传入我们的实例对象,这样便达到了调用我们实例对象方法的目的
所以想象中高大上的动态代理就是这么简单!