有关于动态代理,是一个长盛不衰的话题。无论是面试还是各个框架的应用,都是热点话题。
而关于Dubbo的动态代理,有两种实现方式:一种是JDK,另一种是Javassist。
本文来介绍下JDK动态代理的使用方式,并简单分析下其源码实现。
1.JDK动态打理示例 1.1 创建接口及实现类// 接口
public interface Subject {
String say(String name);
}
// 实现类
public class RealSubject implements Subject {
@Override
public String say(String name) {
return "hello " + name;
}
}
1.2 创建动态代理及测试
public static void main(String[] args) {
Subject realSubject = new RealSubject();
// 通过Proxy.newProxyInstance来创建
Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在真正调用realSubject 方法的前后,执行自定义方法
System.out.println("before invoke...");
Object res = method.invoke(realSubject, args);
System.out.println("after invoke...");
return res;
}
});
String hello = subject.say("jack");
System.out.println(hello);
}
// 结果:
before invoke...
after invoke...
hello jack
通过一个简单的示例,了解下JDK的动态代理Proxy的使用。
那么Proxy.newProxyInstance()方法返回的究竟是什么呢?进入方法源码后可以看到返回的是Object,我们还可以通过类型强转将Object转换为我们的接口类型Subject,那么说明这个Object应该是Subject的实现类。如何验证呢?
2.分析Proxy.newProxyInstance()返回值我们在这个方法进行debug,可以看到,最终返回的是$Proxy0对象,这个是动态生成的类。我们可以通过HSDB来查看这个类的具体内容
2.1 $Proxy0具体内容以下代码进行了format,通过反编译工具出来的代码格式有点乱。
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0
extends Proxy
implements Subject {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
static {
try {
// 分别对应Object的一些基本方法和我们代理的接口的方法
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[]{Class.forName("java.lang.Object")});
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("xw.demo.proxy.Subject").getMethod("say", new Class[]{Class.forName("java.lang.String")});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
} catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
} catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
public final boolean equals(Object paramObject) {
try {
return ((Boolean) this.h.invoke(this, m1, new Object[]{paramObject})).booleanValue();
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString() {
try {
return (String) this.h.invoke(this, m2, null);
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode() {
try {
return ((Integer) this.h.invoke(this, m0, null)).intValue();
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
// 重点在这里
public final String say(String paramString) {
try {
// 通过调用h.invoke()方法来实现
// m3即xw.demo.proxy.Subject接口的say()方法对应的Method对象
return (String) this.h.invoke(this, m3, new Object[]{paramString});
} catch (Error | RuntimeException localError) {
throw localError;
} catch (Throwable localThrowable) {
throw new UndeclaredThrowableException(localThrowable);
}
}
}
通过生成类$Proxy0的查看,其实现了Subject接口,并继承了Proxy对象。
那么这个h是什么呢?就是我们在测试代码中创建的InvocationHandler接口。
通过$Proxy0的构造方法
public $Proxy0(InvocationHandler paramInvocationHandler) {
// 调用了父类的方法
super(paramInvocationHandler);
}
public class Proxy implements java.io.Serializable {
protected InvocationHandler h;
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
}
2.2 $Proxy0.say()
通过对生成代码的分析,由于$Proxy0实现了Subject接口,故其可以强转为Subject。
而$Proxy0.say()的调用本质上 还是调用了我们实现的InvocationHandler.invoke()方法
this.h.invoke(this, m3, new Object[]{paramString})
而我们自定义的InvocationHandler.say()
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在真正调用realSubject 方法的前后,执行自定义方法
System.out.println("before invoke...");
Object res = method.invoke(realSubject, args);
System.out.println("after invoke...");
return res;
}
最终调用到被代理对象realSubject。
这样就完成了对代理对象的调用,并实现了自己的新增功能。
2.3 Proxy.newProxyInstance()源码分析最后,我们来看下,这个神奇的$Proxy0是如何生成的
public class Proxy implements java.io.Serializable {
/**
* a cache of proxy classes
*/
private static final WeakCache>
proxyClassCache = new WeakCache(new KeyFactory(), new ProxyClassFactory());
protected InvocationHandler h;
public static Object newProxyInstance(ClassLoader loader,
Class[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class[] intfs = interfaces.clone();
...
// 重点在这里
Class cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
...
return cons.newInstance(new Object[]{h});
} ...
}
}
2.3.1 Proxy.getProxyClass0()
public class Proxy implements java.io.Serializable {
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就是一个proxy的缓存池,如果缓存池中已经存在该接口的Proxy对象,则直接返回;否则通过ProxyClassFactory创建一个。
2.3.2 WeakCache.get()
final class WeakCache {
// 重要属性,通过构造方法传送过来的
// 而在Proxy对象中,subKeyFactory和valueKeyFactory通过
// proxyClassCache = new WeakCache(new KeyFactory(), new ProxyClassFactory());来设置的
private final BiFunction subKeyFactory;
private final BiFunction valueFactory;
public WeakCache(BiFunction subKeyFactory,
BiFunction valueFactory) {
this.subKeyFactory = Objects.requireNonNull(subKeyFactory);
this.valueFactory = Objects.requireNonNull(valueFactory);
}
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
...
// 关键点在这里 subKeyFactory.apply(key, parameter)
// 这里的subKeyFactory 即Proxy.KeyFactory,其apply方法具体内容见2.3.2.1
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier supplier = valuesMap.get(subKey);
Factory factory = null;
while (true) {
// 初始时supplier为空
if (supplier != null) {
// 最终调用到WeakCache.Factory.get()方法,具体见2.3.2.2
V value = supplier.get();
if (value != null) {
return value;
}
}
if (factory == null) {
// 这里的Factory
factory = new Factory(key, parameter, subKey, valuesMap);
}
if (supplier == null) {
// 将subKey和Factory组装成supplier
// 然后再通过循环,调用到上面supplier.get()
supplier = valuesMap.putIfAbsent(subKey, factory);
if (supplier == null) {
supplier = factory;
}
} else {
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);
}
}
}
}
}
2.3.2.1 WeakCache.KeyFactory
private static final class KeyFactory
implements BiFunction[], Class>
{
// prefix for all proxy class names
private static final String proxyClassNamePrefix = "$Proxy";
// next number to use for generation of unique proxy class names
private static final AtomicLong nextUniqueNumber = new AtomicLong();
@Override
public Class apply(ClassLoader loader, Class[] interfaces) {
Map interfaceClass = null;
try {
// 这里的interface,即我们在Proxy.newProxyInstance()中传入的接口
interfaceClass = Class.forName(intf.getName(), false, loader);
} catch (ClassNotFoundException e) {
}
...
}
String proxyPkg = null; // package to define proxy class in
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
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");
}
}
}
// 生成包名 com.sun.proxy.
if (proxyPkg == null) {
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
// 生成proxy类名 com.sun.proxy.$Proxy0
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 最终通过ProxyGenerator.generateProxyClass生成proxy类文件
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 生成一个可用类
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
绕了这么一大圈,我们看到最终的结果了,就是通过ProxyGenerator.generateProxyClass()方法来生成对应接口的Proxy类信息。具体内容就是我们在2.1中展示的。
那么我们自定义的InvocationHandler是如何被塞入到这个$Proxy0中的呢?
让我们回到Proxy.newProxyInstance()方法中
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);
}
// 获取$Proxy0的构造方法,入参只有一个InvocationHandler的构造方法
final Constructor cons = cl.getConstructor(constructorParams);
...
// 通过构造方法将我们自定义的InvocationHandler传入,构造出$Proxy0对象
return cons.newInstance(new Object[]{h});
} ...
}
总结:
本来以为很简单的Proxy,没想到有这么多东西要写。
针对动态代理,基本都是一样的套路,生成新的字节码类,并实例化。