零 前期准备
0 FBI WARNING
文章异常啰嗦且绕弯。
1 版本
JDK 版本 : AdoptOpenJDK 15
IDE : idea 2020.3
2 jdk 代理简介
jdk Proxy 是 java 中被广泛使用的动态代理工具之一(另外还有 javaassist 或者 cglib 这一类的字节码技术)。
由于静态代理本身定制化程度比较高,在工程代码中会很繁复,所以对于需要泛用性的框架来说,普遍会使用动态代理。
一 Demo
被代理的接口:
/**
* 被代理的接口
*/
public interface ProxyDemoInterface {
void printHello();
void printHello2();
}
Demo 类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyDemo {
/**
* 测试的 main 方法
**/
public static void main(String[] args) {
// 获取 proxy 工厂
JdkDynamicProxy proxy = new JdkDynamicProxy(new ProxyDemoClass());
// 获取被代理的对象
ProxyDemoInterface proxyInt
= (ProxyDemoInterface) Proxy
.newProxyInstance (
ProxyDemoClass.class.getClassLoader(),
ProxyDemoClass.class.getInterfaces(),
proxy
);
// 调用被代理的方法
proxyInt.printHello();
proxyInt.printHello2();
}
}
/**
* 接口的实现类
**/
class ProxyDemoClass implements ProxyDemoInterface {
@Override
public void printHello() {
System.out.println("hello");
}
@Override
public void printHello2() {
System.out.println("hello2");
}
}
/**
* 代理工厂类
**/
class JdkDynamicProxy implements InvocationHandler {
private Object target;
public JdkDynamicProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("do before");
// 这里可以通过 method.getName 等方法对要代理的方法去做一层筛选
// 如果不筛选的话,默认代理所有的方法
Object result = method.invoke(target,args);
System.out.println("do after");
return result;
}
}
二 Proxy
1 newProxyInstance
// java.lang.reflect.Proxy
// step 1
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class>[] interfaces,
InvocationHandler h) {
// 判断非空,略过
Objects.requireNonNull(h);
// 判断权限,略过
final Class> caller = System.getSecurityManager() == null
? null
: Reflection.getCallerClass();
// 获取代理对象的构造器对象,详见 step 3
Constructor> cons = getProxyConstructor(caller, loader, interfaces);
// 核心构造代理对象的逻辑,详见 step 2
return newProxyInstance(caller, cons, h);
}
// step 2
// 当前方法的核心是使用构造器对象反射创建一个代理对象实例
private static Object newProxyInstance(Class> caller, Constructor> cons,
InvocationHandler h) {
try {
// 此处进行权限控制,如果没有权限设置的话,此处 caller 为 null
if (caller != null) {
checkNewProxyPermission(caller, cons.getDeclaringClass());
}
// 用构造器创建对象
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);
}
}
}
// step 3
// 获取构造器
private static Constructor> getProxyConstructor(Class> caller,
ClassLoader loader,
Class>... interfaces) {
if (interfaces.length == 1) {
// 如果当前被代理对象的父接口只有一个
Class> intf = interfaces[0];
// 此处判断权限,依然略过
if (caller != null) {
checkProxyAccess(caller, loader, intf);
}
// proxyCache 是一个 ClassLoaderValue 类型的对象
// 本质上是一个接口和 classloader 对应构造器的缓存,如果都没有就新建一个
// ProxyBuilder 使用 classloader 和 ClassLoaderValue 的 key 创建一个 Proxy 并存入 CLassLoaderValue 里
// clv 是 proxyCache,ld 是 classloader
return proxyCache.sub(intf).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
} else {
// 接口类不止一个的情况下,需要把接口封装成一个列表,其它逻辑差不多
final Class>[] intfsArray = interfaces.clone();
if (caller != null) {
checkProxyAccess(caller, loader, intfsArray);
}
final List> intfs = Arrays.asList(intfsArray);
return proxyCache.sub(intfs).computeIfAbsent(
loader,
(ld, clv) -> new ProxyBuilder(ld, clv.key()).build()
);
}
}
三 ClassLoaderValue
ClassLoaderValue 是 jdk9 中新增的工具,所以在 jdk8 里 proxyCache 是一个 WaekCache 类型的对象。
1 ClassLoaderValue
package jdk.internal.loader;
import java.util.Objects;
import java.util.function.BiFunction;
public final class ClassLoaderValue
extends AbstractClassLoaderValue, V> {
public ClassLoaderValue() {}
/**
* key 就是自身
*/
@Override
public ClassLoaderValue key() {
return this;
}
/**
* 比较两个 classloadervalue 是否相等
*/
@Override
public boolean isEqualOrDescendantOf(AbstractClassLoaderValue, V> clv) {
return equals(Objects.requireNonNull(clv));
}
}
绝大多数的逻辑被封装在 AbstractClassLoaderValue 中。
2 AbstractClassLoaderValue.Sub
Sub 是 AbstractClassLoaderValue 的内部类,同时也是 AbstractClassLoaderValue 的子类。当 proxyCache 调用 sub(...) 方法的时候,其实相当于创建了一个 Sub 对象。
// jdk.internal.loader.AbstractClassLoaderValue
public AbstractClassLoaderValue.Sub sub(K key) {
return new AbstractClassLoaderValue.Sub(key);
}
Sub 对象的 key 是传入的接口列表。
四 ProxyBuilder
ProxyBuilder 是 Proxy 的内部类,顾名思义,是一个创建者模式用来创建 Proxy 对象的工具封装。
1 构造器
// java.lang.reflect.Proxy.ProxyBuilder
// step 1
// 常用构造器
ProxyBuilder(ClassLoader loader, Class> intf) {
// 详见 step 2
this(loader, Collections.singletonList(intf));
}
// step 2
// 具体实现
ProxyBuilder(ClassLoader loader, List> interfaces) {
// 判断是否虚拟机启动完成
if (!VM.isModuleSystemInited()) {
throw new InternalError("Proxy is not supported until "
+ "module system is fully initialized");
}
// 接口数量小于 65535
if (interfaces.size() > 65535) {
throw new IllegalArgumentException("interface limit exceeded: "
+ interfaces.size());
}
Set> refTypes = referencedTypes(loader, interfaces);
// IAE if violates any restrictions specified in newProxyInstance
validateProxyInterfaces(loader, interfaces, refTypes);
this.interfaces = interfaces;
this.module = mapToModule(loader, interfaces, refTypes);
assert getLoader(module) == loader;
}
2 build
// java.lang.reflect.Proxy.ProxyBuilder
// step 1
Constructor> build() {
// 此处通过处理字节码生成一个新的代理类 class 对象,详见 step 2
Class> proxyClass = defineProxyClass(module, interfaces);
final Constructor> cons;
try {
// 从 class 中获得对应的构造器对象
cons = proxyClass.getConstructor(constructorParams);
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
return cons;
}
// step 2
// 此处 module 是 jdk9 中增加的模块机制,此处略过
// interfaces 是要被代理的实现类的所有实现的接口
private static Class> defineProxyClass(Module m, List> interfaces) {
String proxyPkg = null;
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
for (Class> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
accessFlags = Modifier.FINAL; // non-public, final
String pkg = intf.getPackageName();
if (proxyPkg == null) {
proxyPkg = pkg;
} else if (!pkg.equals(proxyPkg)) {
throw new IllegalArgumentException("non-public interfaces from different packages");
}
}
}
// 这里确定要生成的代理内部类的包名
// 一般来说如果没有模块干扰则是 com.sun.proxy
if (proxyPkg == null) {
proxyPkg = m.isNamed() ? PROXY_PACKAGE_PREFIX + "." + m.getName()
: PROXY_PACKAGE_PREFIX;
} else if (proxyPkg.isEmpty() && m.isNamed()) {
throw new IllegalArgumentException("Unnamed package cannot be added to " + m);
}
// 验证一下包名和类名的合理性,类名一定要包含包名
// 理论上存在,实际上应该不会出现这样的情况
if (m.isNamed()) {
if (!m.getDescriptor().packages().contains(proxyPkg)) {
throw new InternalError(proxyPkg + " not exist in " + m.getName());
}
}
// 这里确定创建类的类名
// num 是一个原子化递增的序号,为了防止重名
long num = nextUniqueNumber.getAndIncrement();
// 一般情况下为 com.sun.proxy.$Proxy0
// 最后一位 0 是递增出来的,如果有多个可能会是其它数字
String proxyName = proxyPkg.isEmpty()
? proxyClassNamePrefix + num
: proxyPkg + "." + proxyClassNamePrefix + num;
// 获取模块的专属 classloader
ClassLoader loader = getLoader(m);
trace(proxyName, m, loader, interfaces);
// 此处通过 ProxyGenerator 生成 class 的字节码,并通过 classloader 生成 class 对象
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(loader, proxyName, interfaces, accessFlags);
try {
Class> pc = JLA.defineClass(loader, proxyName, proxyClassFile,
null, "__dynamic_proxy__");
reverseProxyCache.sub(pc).putIfAbsent(loader, Boolean.TRUE);
return pc;
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
五 ProxyGenerator
ProxyGenerator 是 jdk 底层生成字节码的工具。
1 generateProxyClass
// java.lang.reflect.ProxyGenerator
// step 1
static byte[] generateProxyClass(ClassLoader loader, final String name, List> interfaces, int accessFlags) {
// 创建一个 ProxyGenerator 对象,并通过 generateClassFile() 方法获取 class 字节码
ProxyGenerator gen = new ProxyGenerator(loader, name, interfaces, accessFlags);
// 详见 step 2
final byte[] classFile = gen.generateClassFile();
// 配置是否保存生成的字节码,如果这个配置项为 true 则保存在本地磁盘上
// 此处略过,不是重点
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
try {
int i = name.lastIndexOf(46);
Path path;
if (i > 0) {
Path dir = Path.of(ProxyGenerator.dotToSlash(name.substring(0, i)));
Files.createDirectories(dir);
path = dir.resolve(name.substring(i + 1) + ".class");
} else {
path = Path.of(name + ".class");
}
Files.write(path, classFile, new OpenOption[0]);
return null;
} catch (IOException var4) {
throw new InternalError("I/O exception saving generated file: " + var4);
}
}
});
}
return classFile;
}
// step 2
private byte[] generateClassFile() {
// 写入版本号、类名等信息
this.visit(58, this.accessFlags, dotToSlash(this.className), (String)null, "java/lang/reflect/Proxy", typeNames(this.interfaces));
this.addProxyMethod(hashCodeMethod);
this.addProxyMethod(equalsMethod);
this.addProxyMethod(toStringMethod);
// 处理接口
Iterator var1 = this.interfaces.iterator();
while(var1.hasNext()) {
Class> intf = (Class)var1.next();
Method[] var3 = intf.getMethods();
int var4 = var3.length;
for(int var5 = 0; var5 < var4; ++var5) {
Method m = var3[var5];
if (!Modifier.isStatic(m.getModifiers())) {
this.addProxyMethod(m, intf);
}
}
}
// 处理方法
var1 = this.proxyMethods.values().iterator();
List sigmethods;
while(var1.hasNext()) {
sigmethods = (List)var1.next();
checkReturnTypes(sigmethods);
}
this.generateConstructor();
var1 = this.proxyMethods.values().iterator();
while(var1.hasNext()) {
sigmethods = (List)var1.next();
Iterator var8 = sigmethods.iterator();
while(var8.hasNext()) {
ProxyGenerator.ProxyMethod pm = (ProxyGenerator.ProxyMethod)var8.next();
this.visitField(10, pm.methodFieldName, "Ljava/lang/reflect/Method;", (String)null, (Object)null);
pm.generateMethod(this, this.className);
}
}
this.generateStaticInitializer();
return this.toByteArray();
}
generateClassFile() 的核心即为将字节码所需要的元素都写成一个字符串并转化为字节数组输出。太过繁琐,不做过多深入理解。
六 总结
jdk 动态代理本质上是 jdk 通过字符串拼装模式生成了一个 Proxy 的匿名内部类的二进制 class 流,并使用 classloader 将它加载成了一个 class,然后通过反射将其实例化出来。
本文仅为个人的学习笔记,可能存在错误或者表述不清的地方,有缘补充