零 后期筹备
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<Class<?>> 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<V>
extends AbstractClassLoaderValue<ClassLoaderValue<V>, V> {public ClassLoaderValue() {}
/**
* key 就是本身
*/
@Override
public ClassLoaderValue<V> 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 <K> AbstractClassLoaderValue<CLV, V>.Sub<K> 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<Class<?>> 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<Class<?>> 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<Void>() {public Void run() {cons.setAccessible(true);
return null;
}
});
return cons;
}
// step 2
// 此处 module 是 jdk9 中减少的模块机制,此处略过
// interfaces 是要被代理的实现类的所有实现的接口
private static Class<?> defineProxyClass(Module m, List<Class<?>> 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<Class<?>> 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<Void>() {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,而后通过反射将其实例化进去。
本文仅为集体的学习笔记,可能存在谬误或者表述不清的中央,有缘补充