在 java 中,动态代理算的上是底层架构的发动机。最熟悉的包括 Spring 的 aop、rpc 的实现中也都少不了它的影子。所以,从源码的角度对 jdk 实现的动态代理加以总结。
public interface Developer {
void code();
}
public class JavaDeveloper implements Developer{
private String name;
JavaDeveloper(String name){
this.name = name;
}
@Override
public void code() {
System.out.println(this.name+"is coding java");
}
}
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); //代码行 1
JavaDeveloper zack = new JavaDeveloper("Zack");
Developer zackProxy = (Developer) Proxy.newProxyInstance(zack.getClass().getClassLoader(),//代码行2
zack.getClass().getInterfaces(), ((proxy, method, args1) -> {
System.out.println(proxy.getClass());
if (method.getName().equals("code")) {
System.out.println("Zack is praying for the code!");
return method.invoke(zack, args);
}
if (method.getName().equals("debug")) {
System.out.println("Zack's have no bug!No need to debug!");
return null;
}
return null;
}));
zackProxy.code();
}
}
"C:\Program Files\Java\jdk1.8.0_221\bin\java.exe"
class com.sun.proxy.$Proxy0
Zack is praying for the code!
Zackis coding java
Process finished with exit code 0
整个动态代理的过程,其实就是一个代理类对象的生成过程,而这一过程就是在“代码行 2”中完成的。我精简了这个函数,如下:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException {
Class<?> cl = getProxyClass0(loader, intfs);//获得代理类,代码行3
return cons.newInstance(new Object[]{h});//获得代理类的对象
}
其实这个函数真正发挥作用的就是这两行代码,其他的包括它的注解在内,都是一些校验和对操作权限的判断。继续对“代码行 3”向下追溯。
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new 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);
}
代理 Class 的获取,使用了缓存来处理:WeakCache。它是一个弱引用缓存,通过向它的构造函数传入两个工厂类的对象完成了初始化。仔细向下看的话,KeyFactory 和 ProxyClassFactory 均采用函数式接口的方式实现了工厂模式,那么整个 WeakCache 的构造过程,也就是一个抽象工厂。KeyFactory 主要是获取接口(有可能多个)的散列码,而 ProxyClassFactory 则是代理类的生成过程。
private static final class KeyFactory
implements BiFunction<ClassLoader, Class<?>[], Object>
{
@Override
public Object apply(ClassLoader classLoader, Class<?>[] interfaces) {
switch (interfaces.length) {
case 1: return new Key1(interfaces[0]); // the most frequent
case 2: return new Key2(interfaces[0], interfaces[1]);
case 0: return key0;
default: return new KeyX(interfaces);
}
}
}
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) {
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;//java的描述符是通过2进制的方式实现的,标识明确,速度快,值得借鉴
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) {
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
//获取动态代理的class文件,代码行4
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
//将动态代理clss文件加载进内存
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
}
}
再回过头看一眼,整个 WeakCache 架构。它最主要的是一个二维映射表,最外层 key 是 ClassLoader,subKey 是传入 interfaces 的 hash 值,value 是生成的代理类。key 值均采用弱引用处理,防止存储太多导致 OOM。关于弱引用 WeakReference,可以看java 强引用、软引用、弱引用、虚引用以及 FinalReference
final class WeakCache<K, P, V> {
private final ReferenceQueue<K> refQueue
= new ReferenceQueue<>();//引用队列
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
= new ConcurrentHashMap<>();//真正的缓存用map
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
= new ConcurrentHashMap<>();// 缓存失效机制
private final BiFunction<K, P, ?> subKeyFactory;
private final BiFunction<K, P, V> valueFactory;
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
BiFunction<K, P, V> valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();//清理map中已经没有引用对象的WeakReference
Object cacheKey = CacheKey.valueOf(key, refQueue);//生成key值得WeakReference引用
// lazily install the 2nd level valuesMap for the particular cacheKey
ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
if (valuesMap == null) {
ConcurrentMap<Object, Supplier<V>> oldValuesMap
= map.putIfAbsent(cacheKey,
valuesMap = new ConcurrentHashMap<>());
if (oldValuesMap != null) {
valuesMap = oldValuesMap;
}
}
//生成subKey,也就是调用上面的KeyFactory的apply方法
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
if (supplier != null) {
// supplier might be a Factory or a CacheValue<V> instance
V value = supplier.get();
if (value != null) {
return value;
}
}
// 懒加载一个Factory,这个Factory在内部调用了ProxyClassFactory
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
supplier = valuesMap.get(subKey);
}
}
}
}
}
查看“代码行 4”,是这行生成了动态代理的类文件。其中有个 boolean 类型:saveGeneratedFiles,是它控制了,是否输出 class 文件。所以我们在“代码行 1”中,将这个参数置为 true。
private static final boolean saveGeneratedFiles = (Boolean)AccessController.doPrivileged(new GetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
public static byte[] generateProxyClass(final String var0, Class<?>[] var1, int var2) {
ProxyGenerator var3 = new ProxyGenerator(var0, var1, var2);
final byte[] var4 = var3.generateClassFile();
if (saveGeneratedFiles) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
try {
int var1 = var0.lastIndexOf(46);
Path var2;
if (var1 > 0) {
Path var3 = Paths.get(var0.substring(0, var1).replace('.', File.separatorChar));
Files.createDirectories(var3);
var2 = var3.resolve(var0.substring(var1 + 1, var0.length()) + ".class");
} else {
var2 = Paths.get(var0 + ".class");
}
Files.write(var2, var4, new OpenOption[0]);
return null;
} catch (IOException var4x) {
throw new InternalError("I/O exception saving generated file: " + var4x);
}
}
});
}
如果不做特殊处理的话,默认是在 com.sun.proxy 目录下,生成 Proxy0.class 文件。通过 javap -c '.Proxy0.class' 可以查看它的字节码。简单点,通过 idea 反编译出它的代码。
可以清楚看到,这个类同样实现了 Developer 接口,拥有一个带有 InvocationHandler 参数的构造函数,code()方法以及其他 Object 都有的方法。
以上。。。