前言
看了上一遍 《动态代理模式一》应该会有如下疑问:
- 动态代理实现类实例是怎么生成的?
- 是通过生成Java文件->编译成class文件->ClassLoad->new 对象;还是直接生成class文件->ClassLoad->new 对象?
一、代理类UML类图
这个类图是根据上一遍 动态代理模式一 的代码来绘制的,$Proxy0类是被JVM生成的,全局流程先说一下,让大家在脑海里有一个全局观
- 客户端调用DynamicProxy#newProxyInstance()方法生成代理类$Proxy0实例,这个$Proxy0类是继承Proxy类并实现了HouseSubject接口
- 客户端继续执行$Proxy0#rent()方法就会执行方法体内的DynamicProxy#invoke()方法了,invoke()方法里使用了反射执行了具体RealHouseSubjectA#rent()方法或者是RealHouseSubjectB#rent()方法
二、$Proxy0.class是怎么生成的?
public class Client {
public static void main(String[] args) {
// 添加这行代码,会在项目跟目录下com.sun.proxy看到$Proxy0.class;idea打开会自动反编译
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 创建一个动态代理
DynamicProxy dynamicProxy = new DynamicProxy();
// 创建两个目标对象(房东A和房东B)
HouseSubject subjectA = new RealHouseSubjectA();
HouseSubject subjectB = new RealHouseSubjectB();
// 动态代理拿到相应的操作权限:也就是一个中介有出租多套房子的权限
HouseSubject proxyA = (HouseSubject) dynamicProxy.newProxyInstance(subjectA);
HouseSubject proxyB = (HouseSubject) dynamicProxy.newProxyInstance(subjectB);
// 通过调用动态代理对象方法从而调用目标对象方法
proxyA.rent();
proxyB.rent();
}
}
注意看第五行代码,是本次新增的代码
部分代码截图,红框重点部分
三、实现原理分析
上图为生成代理对象主要方法调用链,我们依次对各个阶段进行分析,说明一下:以下代码只留下核心代码,以下断言,异常判断,安全检查等代码都去掉,目前主要是为了清晰和节约篇幅
Proxy.newProxyInstance()
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
final Class<?>[] intfs = interfaces.clone();
/*
* Look up or generate the designated proxy class.
*/
// 根据提供的接口(intfs:HouseSubject接口),生成代理类
Class<?> cl = getProxyClass0(loader, intfs);
final Constructor<?> cons = cl.getConstructor(constructorParams);
// 调用代理类的构造方法,返回实例对象(示例中:继承了Proxy并实现了HouseSubject接口)
return cons.newInstance(new Object[]{h});
}
Proxy.getProxyClass0()
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
// 已经生成的代理类放入缓存里,如果没有则由ProxyClassFactory创建
return proxyClassCache.get(loader, interfaces);
}
ProxyClassFactory.apply()
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
// 1.确定包名,如果没有非public的代理接口,则包名为com.sun.proxy
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
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) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* Choose a name for the proxy class to generate.
*/
// 2.确定类名,示例中代理类名为:com.sun.proxy.$Proxy0
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* Generate the specified proxy class.
*/
// 3.根据类名,代理接口信息生成代理类,即jvm字节码.class文件
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
// 4.根据生成的.class文件,返回一个代理类Class;此方法为本地方法
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
}
四、总结
文章一开始全局的介绍JDK动态代理脉络,紧接着分析实现原理,主要以源码核心代码进行讲解,没有每一行代码进行注释讲解,大家最好debug一下,加深印象~