在Java动态代理(一),我们了解了代理模式的含义,也用程序演示了静态代理和动态代理的实现。现在,我们就来学习一下java动态代理的源码。
代理类的字节码查看
我们知道,jdk动态代理是在程序运行的时候动态生成代理类,那么生成的代理类里面是什么样的了。我们可以通过下面的方式获得生成的代理类的字节码,然后通过反编译查看代理类的内容。
package com.code.proxy;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* 获取动态代理类的字节码
*/
public class DymaticProxyCode {
public static void main(String[] args) throws Exception {
// 1.设置saveGeneratedFiles值为true则生成 class字节码文件方便分析
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 2.获取动态代理类
Class<?> proxyClazz = Proxy.getProxyClass(Star.class.getClassLoader(), Star.class);
// 3.获得代理类的构造函数,并传入参数类型InvocationHandler.class
Constructor<?> constructor = proxyClazz.getConstructor(InvocationHandler.class);
// 4.通过构造函数来创建动态代理对象,将自定义的InvocationHandler实例传入
StarProxyHandler handler = new StarProxyHandler();
handler.bind(new LiuDehua());
Star star = (Star) constructor.newInstance(handler);
// 5.通过代理对象调用目标方法
star.sing();
}
}
由于动态代理类的默认包路径是com.sun.proxy,为了存储字节码,我们需要在项目根路径新建目录com/sun/proxy,否则程序会报错。
通过反编译,我们先来看一下动态代理类的内容:
package com.sun.proxy;
import com.code.proxy.Star;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class Proxy0 extends Proxy
implements Star
{
private static Method m1;
private static Method m4;
private static Method m3;
private static Method m0;
private static Method m2;
public Proxy0()
throws
{
super(paramInvocationHandler);
}
public final boolean equals()
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void dance()
throws
{
try
{
this.h.invoke(this, m4, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void sing()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return ((String)this.h.invoke(this, m2, null));
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m4 = Class.forName("com.code.proxy.Star").getMethod("dance", new Class[0]);
m3 = Class.forName("com.code.proxy.Star").getMethod("sing", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
我们看到,代理类里面主要包括以下内容:
- 代理类的构造函数会传递一个InvocationHandler对象
- 代理类里面会实现接口的sing、dance方法,另外还有equals、hashCode、toString方法(这三个方法其实是继承Object,每个代理类都会实现)
- 代理类里面方法的实现,最终都会调用this.h.invoke,也就是说对代理对象的调用最终实际调用的是InvocationHandler对象
- 代理类继承Proxy,实现Star接口(目标接口)
Proxy源码解析
1. 首先,从Proxy.getProxyClass(Star.class.getClassLoader(), Star.class)进入查看。
public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces){
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
return getProxyClass0(loader, intfs);
}
private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {
//接口数目不能大于65535
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
//首先,会从缓存获取代理类。如果缓存里面没有,则会通过ProxyClassFactory创建
return proxyClassCache.get(loader, interfaces);
}
2. proxyClassCache.get(loader, interfaces)里面主要是根据不同的classLoader从不同的缓存里面获取代理类的supplier,最后从supplier里面获取代理类
3. supplier属于ProxyClassFactory类,最终会调用ProxyClassFactory.apply
//动态代理工厂类
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>>
{
// 代理类的类名以$Proxy作为前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 为保证代理类类名唯一的一个自增序号
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
//判断该类加载器加载的接口类和需要代理的接口类是同一对象
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
//判断需要代理的接口类是一个interface
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
//判断该接口类是否重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
//代理类的包路径
String proxyPkg = null;
//如果接口不是public类型,则需要校验所有接口的包路径是否一致
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
//判断接口是否是public
if (!Modifier.isPublic(flags)) {
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) {
//如果所有的接口都是public,或者都没指定包路径,则以默认的com.sun.proxy作为代理类的包路径
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
//生成代理类类名的序号
long num = nextUniqueNumber.getAndIncrement();
//代理类包含路径的全类名,eg:com.sun.proxy.$Proxy0
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//生成代理类的class文件
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
try {
//调用native方法加载代理类的class文件,并返回代理类对象
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
4. 从上面的代码可以看到,代理类的class文件的生成逻辑在 ProxyGenerator.generateProxyClass里面。但是,ProxyGenerator在jdk的sun包路径下,而sun路径下的代码并没有开源。我们可以通过反编译或者从openJdk获取这一部分的源码
private byte[] generateClassFile() {
//添加hashCode方法
addProxyMethod(hashCodeMethod, Object.class);
//添加equals方法
addProxyMethod(equalsMethod, Object.class);
//添加toString方法
addProxyMethod(toStringMethod, Object.class);
//从接口获取所有的方法
for (Class<?> intf : interfaces) {
for (Method m : intf.getMethods()) {
addProxyMethod(m, intf);
}
}
//判断同一签名的所有方法的返回类型是否兼容的
//签名 : 方法名+参数
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
}
try {
//添加构造方法
methods.add(generateConstructor());
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// 添加方法的参数
fields.add(new FieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
// 添加代理类的方法
methods.add(pm.generateMethod());
}
}
//添加静态初始化方法 eg:
/* static
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m4 = Class.forName("com.code.proxy.Star").getMethod("dance", new Class[0]);
}*/
methods.add(generateStaticInitializer());
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception");
}
//代理类的方法个数不能超过65535
if (methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
}
//代理类的参数个数不能超过65535
if (fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
}
//生成最终的class文件
...
return bout.toByteArray();
}
5. 代理类生成之后,我们就可以获取代理类的构造方法,然后通过构造方法传递目标对象,最终得到代理对象
//得到代理类的构造函数
Constructor<?> constructor = proxyClazz.getConstructor(InvocationHandler.class);
//实例化代理对象
Star star = (Star) constructor.newInstance(handler);
动态代理实现过程总结
1. 对被代理类做一些校验,如是否为接口、是否属于同一包路径、同一签名的返回类型是否可兼容等
2. 获取目标接口的所有方法和属性,并添加equals、hashCode、toString三个默认方法
3. 根据上述步骤获取的代理类的结构,生成class文件的二进制文件
4. 通过native方法将上述代理类的二进制文件装载到jvm