以下解析参考了以下文章,加入了自己的一点小见解:
JDK动态代理(1)代理模式实现方式的概要介绍
JDK动态代理(2)JDK动态代理的底层实现之Proxy源码分析
JDK动态代理(3)WeakCache缓存的实现机制
JDK动态代理(4)ProxyGenerator生成代理类的字节码文件解析
代理模式
什么是代理模式?
在日常生活中,我们常常会使用到代理模式,比如通过房产中介买房,客户只需要发出一个请求,由代理去处理这个请求,再将结果返回给客户。
为什么使用代理模式?
比如买房,通过中介的话,客户不需要自己去找房源、去沟通等操作,使得买房这一操作更加便利、节省时间。当然客户也可以选择所有事情都自己来完成,但需要考虑两点,一个是是否有足够的时间和精力,二是是否具备足够的资源和能力。
怎么使用代理模式?
Java中有两种方式可以实现代理:静态代理和动态代理。
静态代理
静态代理,即由开发者实现代理类再进行编译,程序运行前,代理类的.class文件就已存在。
实现
1. 首先声明一个接口
public interface Image {
void display();
}
2. 定义目标类,实现该接口
public class RealImage implements Image {
private static final String TAG = "RealImage";
@Override
public void display() {
Log.d(TAG, "display target...");
}
}
3. 定义代理类,也需要实现该接口,并持有目标类的实例对象
public class ProxyImage implements Image {
private static final String TAG = "ProxyImage";
private RealImage realImage;
public ProxyImage(RealImage realImage) {
this.realImage = realImage;
}
@Override
public void display() {
Log.d(TAG, "Before display...");
realImage.display();
Log.d(TAG, "After display...");
}
}
4. 使用代理类处理请求
RealImage realImage = new RealImage();
ProxyImage proxyImage = new ProxyImage(realImage);
proxyImage.display();
- 结果
D/ProxyImage: Before display...
D/RealImage: display image...
D/ProxyImage: After display…
缺点
静态代理虽然实现简单且容易理解,但由于代理类持有目标对象的引用,使得代理对象与目标对象耦合在一起,一个代理类不能作用于多个目标对象。如果一个接口下有多种实现,而每种实现都需要代理的话,就需要重新写代理类,不能重用代码。
动态代理
动态代理,即程序运行时通过反射机制创建的代理。
实现
采用上面的接口来实现动态代理,第1、2步就不重复了。
3. 实现InvocationHandler,在invoke()方法中执行代理行为
public class TransactionHandler implements InvocationHandler {
private static final String TAG = "TransactionHandler";
Object target;
public TransactionHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.d(TAG, "Before invoke target's method...");
Object result = method.invoke(target, args);
Log.d(TAG, "After invoke target's method...");
return result;
}
}
4. 通过Proxy.newProxyInstance()方法生成代理对象并执行
Object realImage = new RealImage();
Image proxyImage = (Image) Proxy.newProxyInstance(realImage.getClass().getClassLoader(),
realImage.getClass().getInterfaces(), new TransactionHandler(realImage));
proxyImage.display();
5. 结果
D/TransactionHandler: Before invoke target's method...
D/RealImage: display target...
D/TransactionHandler: After invoke target's method...
动态代理解析
Proxy.newProxyInstance()
前面实现动态代理中讲到可以使用Proxy
类提供的静态方法newProxyInstance()
来创建一个代理对象,该方法接收3个参数:
- loader : ClassLoader 目标类的类加载器
- interfaces : Class<?>[] 目标类实现的接口集合
- h : InvocationHandler 调用处理器
方法返回一个Object
对象,即我们需要的代理对象。
接下来就从这个方法开始看代理类是怎样被一步一步创造出来的。
private static final Class<?>[] constructorParams =
{ InvocationHandler.class };
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 验证传入的InvocationHandler对象不能为空
Objects.requireNonNull(h);
// 复制代理类实现的所有接口
final Class<?>[] intfs = interfaces.clone();
// 获取安全管理器
final SecurityManager sm = System.getSecurityManager();
// 进行一些权限校验
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 从缓存中获取代理类,如果没有就生成一个
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
// 进行一些权限校验
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 获取参数类型是InvocationHandler的构造器
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;
}
});
cons.setAccessible(true);
}
// 传入InvocationHandler对象,通过构造器构造一个代理对象并返回
// 所有代理类都是继承自Proxy类
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);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
可以看出,Proxy.newProxyInstance()
方法做了以下事情:
- 对传入的参数进行校验
- 调用
getProxyClass0()
方法获取代理类对象 - 通过代理类对象获取带参(
InvocationHandler
)构造器 - 检验构造器是否可以访问,若不可以,就将其设为可访问的
- 传入
InvocationHandler
对象,构造代理对象并返回
这里最重要的就是第2步,获取代理类对象,我们来看看getProxyClass0()
方法做了什么。
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);
}
可以看到这个方法很简单,首先判断接口数是否大于65535,如果是就抛出异常,否则就通过类加载器和接口从缓存中获取类对象。
缓存机制
Proxy
使用了缓存机制来缓存动态代理类,类加载器和实现的接口数组作为key,通过KeyFactory
来构建key,ProxyClassFactory
来构建代理类,后面会详细解说。
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
我们先来看下WeakCache
是怎么实现的。
WeakCache
final class WeakCache<K, P, V> {
// 引用队列,被回收的弱引用会添加到引用队列中
private final ReferenceQueue<K> refQueue
= new ReferenceQueue<>();
// 缓存的实现,key为一级缓存,value为二级缓存
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
= new ConcurrentHashMap<>();
// 记录了所有代理类生成器是否可用的状态
private final ConcurrentMap<Supplier<V>, Boolean> reverseMap
= new ConcurrentHashMap<>();
// 二级缓存key的生成工厂,即Proxy.KeyFactory对象
private final BiFunction<K, P, ?> subKeyFactory;
// 二级缓存value的生成工厂,即Proxy.ProxyClassFactory对象
private final BiFunction<K, P, V> valueFactory;
// 构造器,传入二级缓存key的工厂以及二级缓存value的生成工厂
public WeakCache(BiFunction<K, P, ?> subKeyFactory,
BiFunction<K, P, V> valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
...
}
首先我们看下WeakCache
的成员变量与构造器,WeakCache
缓存的内部实现是由ConcurrentMap
来完成的,成员变量map
是缓存的具体实现,reverseMap
是为了缓存的过期机制存在的,subKeyFactory
与valueFactory
分别是二级缓存key和value的工厂,通过构造器传入,这里传入的即KeyFactory
对象与ProxyClassFactory
对象。
从上面我们知道获取代理类对象的时候,是通过缓存的get()
方法来获取的,那我们便来看下get()
方法做了哪些事。
// Proxy中传入的key为classLoader,parameter为interfaces
public V get(K key, P parameter) {
// 检查接口数组不为空
Objects.requireNonNull(parameter);
// 清除过期缓存
expungeStaleEntries();
// 将classLoader封装为CacheKey作为一级缓存key,CacheKey继承WeakReference
Object cacheKey = CacheKey.valueOf(key, refQueue);
// 构建一级缓存的value,如果为空则新建一个插入map中,调用ConcurrentMap.putIfAbsent,线程安全
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;
}
}
// 调用二级缓存key的工厂生成二级缓存key,并作非空判断
// 这里调KeyFactory.apply()方法
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 从二级缓存中获取subKey对应的值
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
// 采用轮询机制,直到获取到代理类对象才退出循环
while (true) {
if (supplier != null) {
// 如果subKey对应的值不为空,且获取的value也不为空,直接返回该对象
// 这里的值可能是代理类生成器,也可能是代理类对象的弱引用,具体可看后面Factory.get()方法的解析
V value = supplier.get();
if (value != null) {
return value;
}
}
// 缓存未命中,构建一个代理类生成器
if (factory == null) {
factory = new Factory(key, parameter, subKey, valuesMap);
}
// 如果通过key获取的代理类生成器为空,则将新建的代理类生成器对象加入到二级缓存中
// 如果不为空,则用新建的代理类生成器替换旧的,替换失败的话则用旧的生成器
// 因为整个操作不是原子操作,有可能其他线程修改了supplier的值,所以需要做相应的判断
if (supplier == null) {
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
// successfully installed Factory
supplier = factory;
}
// else retry with winning supplier
} else {
if (valuesMap.replace(subKey, supplier, factory)) {
supplier = factory;
} else {
// retry with current supplier
supplier = valuesMap.get(subKey);
}
}
}
}
可以看到,WeakCache.get()
方法并没有作同步处理,它主要通过ConcurrentMap
来实现线程安全,一级缓存、二级缓存使用的都是ConcurrentMap
,从而将get()
方法的同步代码块缩小,有助于提高WeakCache
的性能。接下来看下WeakCache.get()
的具体实现步骤:
- 检查接口数组是否为空;
- 清除过期缓存;
- 将
ClassLoader
的弱引用作为一级缓存的key,我们知道不同的类加载器加载同一个类得到的对象也是不一样的; - 通过
KeyFactory
将接口数组封装为二级缓存的key; - 根据上一步构建的key从二级缓存中获取
supplier
,如果supplier
不为空且获取的值也不为空,则缓存命中,返回该值; - 缓存未命中,构建代理类生成器,其中
supplier
为二级缓存中key对应的值,而factory
为新建的对象,如果supplier
为空,则将factory
插入二级缓存中并赋值给supplier
,否则就用新的factory
替换二级缓存中旧的数据,替换失败则继续使用旧的对象。 - 回到第5步。
那么代理类是在哪里生成的呢?别着急,我们来看下代理类生成器的实现Factory
的实现。
private final class Factory implements Supplier<V> {
// 一级缓存key,即ClassLoader的弱引用
private final K key;
// 接口数组
private final P parameter;
// 二级缓存key
private final Object subKey;
// 二级缓存value
private final ConcurrentMap<Object, Supplier<V>> valuesMap;
Factory(K key, P parameter, Object subKey,
ConcurrentMap<Object, Supplier<V>> valuesMap) {
this.key = key;
this.parameter = parameter;
this.subKey = subKey;
this.valuesMap = valuesMap;
}
@Override
public synchronized V get() { // 加了同步锁,只能串行访问,线程安全
// 重新检查二级缓存
Supplier<V> supplier = valuesMap.get(subKey);
// 二级缓存中key对应的生成器不是自己了
if (supplier != this) {
// 等待锁的时候发生了一些变化,可能是被替换了,或者被移除了,则结束该方法
return null;
}
// create new value
V value = null;
try {
// 调用ProxyClassFactory.apply()方法生成类对象
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) { // 生成失败,则从二级缓存中移除该生成器
valuesMap.remove(subKey, this);
}
}
// 只有value的值不为空才能走到这里
assert value != null;
// 将value封装为CacheValue,CacheValue继承自WeakReference
CacheValue<V> cacheValue = new CacheValue<>(value);
// 用cacheValue替换二级缓存中key对应的代理类生成器,如果失败则抛出异常
if (valuesMap.replace(subKey, this, cacheValue)) {
// 并且把cacheValue添加到reverseMap中
reverseMap.put(cacheValue, Boolean.TRUE);
} else {
throw new AssertionError("Should not reach here");
}
// 返回代理类对象
return value;
}
}
Factory
这个内部工厂类实现了Supplier
接口,具体的都在代码中注释了,有几个点需要注意一下:
-
get()
方法加了同步锁,所以它是线程安全的。 -
get()
方法的开始部分进行了一次检查操作,防止在等待锁的过程中,二级缓存中subKey
对应的值发生了变化:被移除或被替换,则结束该方法,因为这个生成器已经无效了。 - 生成代理类对象后,会将代理类对象封装一下,作为最终的二级缓存中的值,所以在解析
WeakCache.get()
方法中时,我们说通过subKey
获取的值有可能是类对象生成器,也有可能是类对象的弱引用。 - 类对象的构建是在
ProxyClassFactory
中实现的,ProxyClassFactory
是Proxy
类的内部类。
Proxy.ProxyClassFactory
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) {
// 1. 接口是否可以由该ClassLoader加载
Class<?> interfaceClass = null;
try {
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
if (interfaceClass != intf) {
throw new IllegalArgumentException(
intf + " is not visible from class loader");
}
// 2. 是否确实是个接口
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 3. 接口是否重复,这里用到了IdentityHashMap的特性:
// 判断key是否重复使用的是引用相等性,即key1 == key2
// 因此如果put()的返回值不为空,则说明interfaceSet中存在相同key引用,即接口
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;
// 非public的接口,则其代理类与接口同一个包名,
// 确保所有非public的接口都在同一个包名下
for (Class<?> intf : interfaces) {
int flags = intf.getModifiers();
if (!Modifier.isPublic(flags)) {
// 非public的,访问标志则为final
accessFlags = Modifier.FINAL;
// 获取非public接口的包名
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)) {
// 如果非public的接口包名不同,抛出异常
throw new IllegalArgumentException(
"non-public interfaces from different packages");
}
}
}
if (proxyPkg == null) {
// 如果没有非public接口,则使用默认包名
// Java默认使用“com.sun.proxy.”,Android默认为空
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
// 生成代理类的序号
long num = nextUniqueNumber.getAndIncrement();
// 生成代理类的全限定名:包名+前缀+序号,例如:com.sun.proxy.$Proxy0
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 调用ProxyGenerator.generateProxyClass生成字节码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 根据二进制文件生成相应的Class实例
return Proxy.defineClass0(loader, proxyName, proxyClassFile, 0,
proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
ProxyClassFactory
首先遍历接口数组,一一进行校验,主要针对以下三个方面,如果校验失败,则抛出异常:
- 接口是否能由ClassLoader加载;
- 接口是否确实是个接口;
- 接口是否重复
接着,生成代理类的全限定名,其结构为:包名+前缀+序号
- 包名
- 当接口均为
public
时,包名默认为com.sun.proxy.
,访问标志为public final
- 当有接口为
non-public
时,代理类的包名与该接口的包名相同,访问标志为final
。注意,所有的non-public
接口需在同一个包下面,否则抛出异常
- 当接口均为
- 前缀:默认为
$Proxy
- 序号:由原子类生成,确保代理类的唯一性
确定了全限定名与访问标志之后,调用ProxyGenerator.generateProxyClass
生成字节码文件,最后再根据字节码生成Class
实例。
ProxyGenerator
最后,我们来看下,ProxyGenerator
是怎么生成字节码文件的。
public static byte[] generateProxyClass(final String name,
Class<?>[] interfaces,
int accessFlags)
{
// 创建ProxyGenerator实例对象
ProxyGenerator gen = new ProxyGenerator(name, interfaces, accessFlags);
// 调用generateClassFile生成字节码
final byte[] classFile = gen.generateClassFile();
// 省略保存字节码文件的步骤
...
return classFile;
}
ProxyGenerator的静态方法generateProxyClass()就是初始化一个ProxyGenerator实例,然后调用它的generateClassFile()生成字节码,看下generateClassFile()怎么生成字节码的。
private byte[] generateClassFile() {
// Step 1: 将所有方法封装为ProxyMethod对象
// 首先封装Object的三个方法,Java所有类都继承自Object
addProxyMethod(hashCodeMethod, Object.class);
addProxyMethod(equalsMethod, Object.class);
addProxyMethod(toStringMethod, Object.class);
// 接着封装所有接口的方法
for (Class<?> intf : interfaces) {
for (Method m : intf.getMethods()) {
addProxyMethod(m, intf);
}
}
// 对于具有相同签名的代理方法,检验方法的返回值是否兼容
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
checkReturnTypes(sigmethods);
}
// Step 2: 将所有字段和方法封装成FiledInfo对象和MethodInfo对象
try {
// 2.1: 生成带参构造器,并添加到methods集合中
methods.add(generateConstructor());
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// 2.2: 为代理方法添加静态字段,例如:private static Method m1;
fields.add(new FieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
//2.3: 为代理方法生成代码并添加到methods中
methods.add(pm.generateMethod());
}
}
// 2.4: 添加代理类的静态字段初始化方法
methods.add(generateStaticInitializer());
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
// 检查方法数、字段数,不允许超过65535
if (methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
}
if (fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
}
// Step 3: 写入最终的class文件
// 验证常量池中有代理类的全限定名
cp.getClass(dotToSplash(className));
// 验证常量池中有父类的全限定名,父类名为:"java/lang/reflect/Proxy"
cp.getClass(superclassName);
// 验证常量池中存在各个接口的全限定名
for (Class<?> intf: interfaces) {
cp.getClass(dotToSplash(intf.getName()));
}
// 接下来要开始写入文件了,将常量池设为只读
cp.setReadOnly();
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
try {
// 写入类文件的各个部分的数据
// 1. 写入魔数, u4
dout.writeInt(0xCAFEBABE);
// 2. 写入次版本号, u2
dout.writeShort(CLASSFILE_MINOR_VERSION);
// 3. 写入主版本号,u2
dout.writeShort(CLASSFILE_MAJOR_VERSION);
// 4. 写入常量池
cp.write(dout);
// 5. 写入访问标志,u2
dout.writeShort(accessFlags);
// 6. 写入代理类索引,u2
dout.writeShort(cp.getClass(dotToSlash(className)));
// 7. 写入父类索引,u2
dout.writeShort(cp.getClass(superclassName));
// 8. 写入接口数,u2
dout.writeShort(interfaces.length);
// 9. 写入接口索引,u2 * 接口数
for (Class<?> intf : interfaces) {
dout.writeShort(cp.getClass(
dotToSlash(intf.getName())));
}
// 10. 写入字段数,u2
dout.writeShort(fields.size());
// 11. 写入字段集合
for (FieldInfo f : fields) {
f.write(dout);
}
// 12. 写入方法数,u2
dout.writeShort(methods.size());
// 13. 写入方法集合
for (MethodInfo m : methods) {
m.write(dout);
}
// 14. 写入属性数,代理类class文件没有属性,故为0
dout.writeShort(0);
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e)
}
// 转换成二进制数组输出
return bout.toByteArray();
}
可以看到generateClassFile()
方法是按照Class
文件结构进行动态拼接的,生成Class
文件主要分为3步:
- 收集所有要生成的代理方法,将其包装成
ProxyMethod
对象,并添加到map集合中 - 收集所有要为
Class
文件生成的字段信息和方法信息 - 开始组装
Class
文件
我们知道一个类的核心部分就是它的字段和方法,因此我们重点来看下第二步,看看它为代理类生成了哪些字段和方法。在第二步中,按顺序做了下面四件事:
- 为代理类生成一个带参构造器,传入
InvocationHandler
实例的引用并调用父类的带参构造器 - 遍历代理方法
Map
集合,为每个代理方法生成对应的Method
类型静态域,并将其添加到fields
集合中 - 遍历代理方法
Map
集合,为每个代理方法声称对应的MethodInfo
对象,并将其添加到methods
集合中 - 为代理类生成静态初始方法,该静态初始方法主要是将每个代理方法的引用赋值给对应的静态字段
通过以上分析,我们大致可以知道动态代理最终会为我们生成如下结构的代理类:
public class Proxy0 extends Proxy implements Image {
// 第一步,生成构造器
public Proxy0(InvocationHandler h) {
super(h);
}
// 第二步,生成静态字段
private static Method m1; // hashCode方法
private static Method m2; // equals方法
private static Method m3; // toString方法
private static Method m4; // display方法
// 第三步,生成代理方法
@Override
public int hashCode() {
try {
return (int) h.invoke(this, m1, null);
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public boolean equals(Object obj) {
try {
Object[] args = new Object[] {obj};
return (boolean) h.invoke(this, m2, args2);
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public String toString() {
try {
return (String) h.invoke(this, m3, null);
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
@Override
public void display() {
try {
h.invoke(this, m4, null);
} catch (Throwable e) {
throw new UndeclaredThrowableException(e);
}
}
// 第四步,生成静态初始化方法
static {
try {
Class c1 = Class.forName(Object.class.getName());
Class c2 = Class.forName(Image.class.getName());
m1 = c1.getMethod("hashCode", null);
m2 = c1.getMethod("equals", new Class[]{Object.class});
m3 = c1.getMethod("toString", null);
m4 = c2.getMethod("display", null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
至此,经过层层分析,深入探究JDK源码,我们还原了动态生成代理类的真面目,一些疑问也得到了很好的解答:
- 代理类默认继承
Proxy
类,因为Java中只支持单继承,因此JDK动态代理只能实现接口 - 代理方法都会去调用
InvocationHandler
的invoke()
方法,因此我们需要重写InvocationHandler.invoke()
方法 - 调用
invoke()
方法时会传入代理实例本身、目标方法和目标方法参数,解释了invoke()
方法的参数是怎么来的。