参考博客:
https://www.cnblogs.com/liuyun1995/p/8144628.html
https://www.cnblogs.com/liuyun1995/p/8157098.html
https://www.cnblogs.com/liuyun1995/p/8144676.html
https://www.cnblogs.com/liuyun1995/p/8144706.html
https://blog.csdn.net/wangqyoho/article/details/77584832
getProxyClass0()方法
在通过newProxyInstance()方法获取代理对象的过程中 , 有一个比较关键的步骤 , 就是通过getProxyClass0()获取代理类
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
...
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
}
跟进这个方法可以看到首先是一个接口数量的检查,然后是从一个二级缓存中获取代理类,如果缓存中不存在该代理类,则会调用ProxyClassFactory这个工厂去生成一个代理类。
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 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
return proxyClassCache.get(loader, interfaces);
}
ProxyClassFactory工厂类 :
ProxyGenerator.generateProxyClass(proxyName,
interfaces, accessFlags)//代理类生成工厂
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
//代理类名称前缀
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) {
//这里遍历interfaces数组进行验证, 主要做三件事情
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
//1.intf是否可以由指定的类加载进行加载
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
//2.intf是否是一个接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
//3.intf在数组中是否有重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
//生成代理类的包名
String proxyPkg = null;
//生成代理类的访问标志, 默认是public final的
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
for (Class<?> intf : interfaces) {
//获取接口的访问标志
int flags = intf.getModifiers();
//如果接口的访问标志不是public, 那么生成代理类的包名和接口包名相同
if (!Modifier.isPublic(flags)) {
//生成的代理类的访问标志设置为final
accessFlags = Modifier.FINAL;
//获取接口全限定名, 例如:java.util.Collection
String name = intf.getName();
int n = name.lastIndexOf('.');
//剪裁后得到包名:java.util
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
//生成的代理类的包名和接口包名是一样的
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
//代理类如果实现不同包的接口, 并且接口都不是public的, 那么就会在这里报错
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
//如果接口访问标志都是public的话, 那生成的代理类都放到默认的包下:com.sun.proxy
if (proxyPkg == null) {
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
//生成代理类的序号
long num = nextUniqueNumber.getAndIncrement();
//生成代理类的全限定名, 包名+前缀+序号, 例如:com.sun.proxy.$Proxy0
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//这里是核心, 用ProxyGenerator来生成字节码, 该类放在sun.misc包下
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName,
interfaces, accessFlags);
try {
//根据二进制文件生成相应的Class实例
return defineClass0(loader, proxyName, proxyClassFile,
0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
-
代理类工厂生成代理的的过程主要可以分为三步步 :
-
对要代理的接口进行验证(类加载器是否可以加载数组中的接口 , 数组中的对象是否都是接口 , 接口数组是否存在重复接口)
-
设置代理类的包名 ,访问标志 , 类名称 ,并通过ProxyGenerator.generateProxyClass()方法组装生成字节码文件
-
代理类的全限定名 = 报名 + $proxy + 序号
-
如果接口是public的,代理类默认是public final的,并且生成的代理类默认放到com.sun.proxy这个包下。
-
如果接口是非public的,那么代理类也是非public的,并且生成的代理类会放在对应接口所在的包下。
-
如果接口是非public的,并且这些接口不在同一个包下,那么就会报错。
-
-
通过defineClass0()方法根据二进制文件生成相应的Class实例
-