JDK 动态代理的实现
虽然在常用的 Java 框架(Spring、MyBaits 等)中,经常见到 JDK 动态代理的使用,也知道了怎么去写一个 JDK 动态代理的 Demo,但是并不清楚实现原理。
之前略微知道是先生成一个代理对象,然后外部调用代理对象的接口方法,然后代理又会调用原始对象的方法,仅此而已。现在想稍微深入一丢,了解部分实现方式。
Java 程序是运行在 JVM 中的,源码首先编译成字节码,然后加载到虚拟机中,被虚拟机解析然后执行(注意这里的措辞不一定严谨准确,会其意即可)。
JDK 动态代理实际上也就是在代码的运行中动态的生成了实现指定接口(被代理对象实现的接口)的类的字节码,对应的也就是代理类,然后创建这个代理类的对象,也就是代理对象。关于这一部分内容,看这篇博文更好,写的很详细。其实本文关注的点其实是 JDK 是如何创建代理类的,进而找到为什么调用代理对象的方法,就能增强原始对象的方法。
先上简单的 Demo 代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* @author xi
* @date 2018/08/23 12:04
*/
public class DynamicProxyTest {
interface IHello {
void sayHello();
}
static class Hello implements IHello {
@Override
public void sayHello() {
System.out.println("hello world");
}
}
static class DynamicProxy implements InvocationHandler {
Object originalObj;
Object bind(Object originalObj) {
this.originalObj = originalObj;
return Proxy.newProxyInstance(
originalObj.getClass().getClassLoader(),
originalObj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("welcome");
return method.invoke(originalObj, args);
}
}
public static void main(String[] args) {
IHello hello = (IHello) new DynamicProxy().bind(new Hello());
hello.sayHello();
}
}
这个例子是『深入理解 Java 虚拟机』书上的例子,感觉例子中的DynamicProxy
取名不太好,容易误导像我这样的初学者,容易把它看成代理类,实则不然,它只是个InvocationHandler
接口的实现类,不要搞混了。
其实本次想要关注的重点是代理类和代理对象是如何产生的,所以要看看java.lang.reflect.Proxy#newProxyInstance
,因为机器上用的是 JDK 1.8,代码与之前有点小区别,不过问题不大。
@CallerSensitive// 这个注解不懂是啥,Google 一下,还是没懂,先看看文末的参考吧,有懂的同学,麻烦指点一二
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* 生成代理类的地方,需要进去看一看
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
// 创建代理对象
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
//...省略部分不看的内容
}
}
主要想看的是java.lang.reflect.Proxy#getProxyClass0
是如何生成代理类的:
/**
* Generate a proxy class. Must call the checkProxyAccess method
* to perform permission checks before calling this.
*/
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);
}
proxyClassCache
是一个静态变量,缓存了代理类:
/**
* a cache of proxy classes
*/
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
这里需要注意一下创建缓存的构造方法的两个参数,两个参数的类都实现了BiFunction
接口,Java8 的新特性:函数式接口。简单理解就是接口中定义了一个方法,接收两个参数,一顿操作之后,返回一个结果。先看缓存的构造方法:
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
BiFunction<K, P, V> valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
记住subKeyFactory
和valueFactory
这两个变量是啥,马上就会用到。
先看缓存的java.lang.reflect.WeakCache#get
方法,方法比较长,不用全部看,关注几个注释的地方即可,具体细节可自行 Debug:
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
Object cacheKey = CacheKey.valueOf(key, refQueue);
// 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;
}
}
// create subKey and retrieve the possible Supplier<V> stored by that
// subKey from valuesMap 生成 key,subKeyFactory 就是前面提到的函数对象
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
// 上面的注释都写明白了,获取出来的对象的类都实现了 Supplier 接口
V value = supplier.get();
if (value != null) {
return value;
}
}
// else no supplier in cache
// or a supplier that returned null (could be a cleared CacheValue
// or a Factory that wasn't successful in installing the CacheValue)
// lazily construct a Factory
if (factory == null) {// 创建工厂
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {// 用 factory 替换 supplier
if (valuesMap.replace(subKey, supplier, factory)) {
// successfully replaced
// cleared CacheEntry / unsuccessful Factory
// with our Factory
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
生成 key 就不看了,直接看V value = supplier.get();
这行代码,初次调用时,肯定没有缓存,所以先看java.lang.reflect.WeakCache.Factory#get
:
@Override
public synchronized V get() { // serialize access
// re-check
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
// something changed while we were waiting:
// might be that we were replaced by a CacheValue
// or were removed because of failure ->
// return null to signal WeakCache.get() to retry
// the loop
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {// 这个地方的 valueFactory 就是前面说到的 ProxyClassFactory 对象
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // remove us on failure
valuesMap.remove(subKey, this);
}
}
// the only path to reach here is with non-null value
assert value != null;
// wrap value with CacheValue (WeakReference)
CacheValue<V> cacheValue = new CacheValue<>(value);
// put into reverseMap
reverseMap.put(cacheValue, Boolean.TRUE);
// try replacing us with CacheValue (this should always succeed)
if (!valuesMap.replace(subKey, this, cacheValue)) {// 添加缓存
throw new AssertionError("Should not reach here");
}
// successfully replaced us with new CacheValue -> return the value
// wrapped by it
return value;
}
接下来要看的是java.lang.reflect.Proxy.ProxyClassFactory#apply
方法,主要这一行:
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
这是 JDK 提供的生成代理类的工具,反编译出的代码如下:
未完待续,先睡觉....
参考:
- 『深入理解 Java 虚拟机』:第二版,9.2.3 字节码生成技术与动态代理的实现 P-282
- Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM) - 我的程序人生 - CSDN博客
- JVM注解@CallSensitive - HEL_WOR的博客 - CSDN博客