前言
有了静态代理,为什么 Java 还需要动态代理呢?为了解决静态代理存在的以下缺点:
1、代理类和被代理的真实类要实现相同的接口,如果接口增加一个方法,两者都要做修改,不满足"开闭原则";
2、一个代理类只服务于一个接口/真实类,如果要服务多个接口/真实类,就需要多个代理类;
为了解决这两个问题,动态代理把"代理类"与"接口/真实类"解耦,不要求代理类实现接口,而是在运行时动态地创建代理类对象。
代理模式的组成如图1所示:

图1. 代理模式的组成
Client 实际调用的事 Proxy 对象,Proxy 对象持有 RealSubject 引用并且具有 RealSubject 的同名方法。静态代理是预编译了 Proxy 类,动态代理是在运行时创建 Proxy 类对象。
JDK动态代理怎么实现动态地创建Proxy对象?
Java对象都是由JVM根据编译完成的 .class 文件创建的,动态代理要能够动态创建 Proxy 对象且持有 RealSubject 引用,需要完成以下几件事:
1、创建 Proxy 的 .class 文件,加载到 JVM 中,并创建 Class 对象
2、根据 Proxy 的 Class 对象,调用构造器创建 Proxy 对象实例,并具有 RealSubject 的同名方法
3、Proxy 对象直接或间接持有 RealSubject 对象的引用,在调用同名方法时能够调用 RealSubject 的方法
示例代码
1、被代理的接口和实现类
java
// 被代理的接口
public interface UserService {
/**
* 根据ID查询用户对象
* @param id 用户ID
* @return User
*/
User getUserById(Long id);
}
// 被代理的实现类
@Slf4j
public class UserServiceImpl implements UserService {
@Override
public User getUserById(Long id) {
User user = new User().setId(id);
log.info("user ===== {}", user);
return user;
}
}
2、InvocationHandler 接口的实现类
在JDK 8动态代理中,Proxy 需要实现 InvocationHandler 接口。
java
@Slf4j
public class UserInvokeHandler implements InvocationHandler {
// 被代理的对象
private Object target;
public UserInvokeHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.info("before getUserById === class: {}", this.getClass().getName());
Object result = method.invoke(target, args);
log.info("after getUserById === class: {}", this.getClass().getName());
return result;
}
}
3、使用 Proxy.newProxyInstance() 方法创建代理类对象
java
public static void main(String[] args) {
UserInvokeHandler handler = new UserInvokeHandler(new UserServiceImpl());
UserService userService = (UserService) Proxy.newProxyInstance(
handler.getClass().getClassLoader(),
new Class[]{UserService.class},
handler);
userService.getUserById(200L);
System.out.println("userService ==== " + userService.getClass());
}
打印结果如下:
text
21:34:24.718 [main]UserInvokeHandler - before getUserById === class: UserInvokeHandler
21:34:24.718 [main]UserServiceImpl - user ===== User(id=200)
21:34:24.718 [main]UserInvokeHandler - after getUserById === class: UserInvokeHandler
userService ==== class com.sun.proxy.$Proxy3
示例代码中主要有3个步骤:
1、创建需要被代理的接口和实现类
2、创建 InvocationHandler 接口的实现类
3、使用 Proxy.newProxyInstance() 方法创建代理类对象
调用代理对象的方法时,会调用 handler 的 invoke() 方法,并调用 被代理真实类 的同名方法,最后打印的"class com.sun.proxy.$Proxy3"是代理的类名。
下面,我们通过 Proxy.newProxyInstance() 方法的源码,来学习JDK的动态代理过程。
InvocationHandler
在JDK动态代理中,因为 Proxy 对象是动态创建,并不直接持有 RealSubject 的引用,所以让 InvocationHandler 接口的某个实现类持有 RealSubject 引用,从而让 Proxy 持有 RealSubject 的引用。InvocationHandler 接口只有一个方法:
java
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
该方法有三个参数:
- Object proxy:代理类对象
- Method method:被代理的真实类(RealSubject)的方法
- Object[] args:被代理的真实类(RealSubject)方法(Method)的参数
在 InvocationHandler 接口的实现类中,通过实现 invoke 方法对 RealSubject 方法的代理和拦截。
Proxy
这里的 Proxy 类与前面的 代理类(Proxy)含义不同,下面为了避免混淆,下文的 Proxy 类都表示 Java 中的类,前面图1所示的 Proxy 类统一用"代理类"表示
Proxy.newProxyInstance() 方法负责在运行时创建 .class 文件和 class 对象:
java
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException
方法有三个参数,含义如下:
- ClassLoader loader:类加载器,由哪个加载器来加载"代理类"
- Class<?>[] interfaces:一组接口,表示"代理类"要实现的接口
- InvocationHandler h:InvocationHandler 接口的一个具体实现类对象
下面介绍这个方法的源码。
newProxyInstance()
该方法主要分为3步:
1、进行一些必要的安全性检查,
2、创建"代理类"的 class 对象
3、传入 InvocationHandler 参数,使用 class 对象返回构造器,创建代理类的对象实例
源码如下:
java
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h) throws IllegalArgumentException {
// 1、必要的检查
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
// 2、生成所需的代理类 class 对象
Class<?> cl = getProxyClass0(loader, intfs);
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;
}
});
}
// 创建代理对象,传入了 InvocationHandler 对象作为参数
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);
}
}
最关键的是在第2步,查找和创建代理类的 class 对象:
1、可以猜测在 **getProxyClass0() **方法中,一定是先生成了 .class 字节码,再创建了 class 对象。
2、在运行时生成 .class 字节码和创建 class 对象,是很耗时的一个操作,最好的方法是先从缓存中查找,不存在时再去创建。
下面看一下 getProxyClass0() 方法的源码。
getProxyClass0()
该方法中只是从缓存对象 proxyClassCache 中取出 class 对象:
java
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 根据加载器和 Class 从缓存中查找对应的 Class 对象
return proxyClassCache.get(loader, interfaces);
}
proxyClassCache ****在 Proxy 中的定义如下,主要用来缓存 Class 对象:
swift
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
给 WeakCache 类的构造器,传入 KeyFactory、ProxyClassFactory 对象构造而成,下面介绍一下 WeakCache 类。
WeakCache
WeakCache 中关键字段如下:
java
// 存储数据的双层 map,结构为:key : map<subkey,value>,value 是一个 Supplier,用于创建 V 对象
private final ConcurrentMap<Object, ConcurrentMap<Object, Supplier<V>>> map
= new ConcurrentHashMap<>();
// subkey 的 factory
private final BiFunction<K, P, ?> subKeyFactory;
// value 的 factory
private final BiFunction<K, P, V> valueFactory;
从 proxyClassCache 的定义可知:
- K 为 ClassLoader 对象 ------ 类加载器
- P 为 class[] ------ 被代理的接口数组
- V 为 class 对象对象 ------ 最终的代理类
也就是通过"classLoader 和 被代理的目标接口数组",生成一个最终的动态代理类。
proxyClassCache 使用 new KeyFactory() 和 new ProxyClassFactory() 分别作为 subkeyFactory 和 valueFactory,这两个类都是 Proxy 的静态内部类,在下面有介绍。
get()
在前面的 getProxyClass0() 方法中,调用了 proxyClassCache 的 get(K key, P parameter) 方法,方法的源码如下:
java
public V get(K key, P parameter) {
// 简单的检查和清理
Objects.requireNonNull(parameter);
expungeStaleEntries();
// 查找内层的 map,如果不存在就创建一个
Object cacheKey = CacheKey.valueOf(key, refQueue);
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,找到对应的 supplier
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
Supplier<V> supplier = valuesMap.get(subKey);
Factory factory = null;
// while(true) 循环,第一次进入的时候 supplier 为 null,第二次循环后,设置为 factory 对象,不再为 null,创建 V 值
while (true) {
// 如果 supplier 不为 null,创建一个 value,直接返回
if (supplier != null) {
V value = supplier.get();
if (value != null) {
return value;
}
}
// 如果 factory 为 null,就创建一个新的 factory 来代替 supplier
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);
}
}
}
}
这个方法在一个 while(true) 循环中,调用 WeakCache 内部静态类 Factory 的 get 方法,最终返回要生成的代理对象。
#Factory#get()
Factory类的 get() 方法如下:
java
Factory(K key, P parameter, Object subKey,
ConcurrentMap<Object, Supplier<V>> valuesMap) {
this.key = key; // classLoader
this.parameter = parameter;
this.subKey = subKey; // subKey
this.valuesMap = valuesMap; // 外部类中内嵌的 map
}
@Override
public synchronized V get() { // serialize access
// 再次检查
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
return null;
}
// 调用 valueFactory 来创建 V 值
V value = null;
try {
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
// 如果失败,就移除 subKey
if (value == null) {
valuesMap.remove(subKey, this);
}
}
// 检查
assert value != null;
// 把 V 值包装成 弱引用,然后添加进 valuesMap
CacheValue<V> cacheValue = new CacheValue<>(value);
reverseMap.put(cacheValue, Boolean.TRUE);
if (!valuesMap.replace(subKey, this, cacheValue)) {
throw new AssertionError("Should not reach here");
}
return value;
}
这里生成的最终结果,是一个弱引用,目的应该是为了在下一次 GC 的时候都回收掉,避免太多的动态代理类占用内存空间。
从前面 proxyClassCache 的定义可知,valueFactory 实际是 Proxy#ProxyClassFactory 类,查看它和 KeyFactory 的源码。
Proxy#KeyFactory
Proxy#KeyFactory 的作用是把传入的 ClassLoader 和 接口数组 生成一个 key,也就是作为 proxyClassCache 的的 subKey。
java
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);
}
}
}
Proxy#ProxyClassFactory
Proxy#ProxyClassFactory 用于生成"代理类"的 class 对象:
java
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);
// 检查接口数组,保存到一个 map 中,判断有效性:
for (Class<?> intf : interfaces) {
Class<?> interfaceClass = null;
// 1、能够由当前类加载器加载
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、没有重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
// 遍历传入的接口数组,判断是否有多个 non-public 接口来自不同的 package
// 要求 non-public 的接口必须来自同一个 package
String proxyPkg = null;
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");
}
}
}
// 没有 non-public 接口,使用默认的 package 路径
if (proxyPkg == null) {
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
// 生成代理类的类名
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成所需的代理类的字节码
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 加载 class 字节码
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
throw new IllegalArgumentException(e.toString());
}
}
}
经过上述过程之后,最终返回到 Proxy.newProxyInstance() 方法中,生成一个 Class 对象,然后再调用构造器创建对象,最终创建出代理类对象。
代理类字节码
我们知道了创建代理类对象的过程,符合我们之前的假设步骤类似:创建 .class 文件字节码、生成 class 文件、调用构造器创建对象。
还有一个问题没有解决: 代理类是怎么持有 RealSubject 的引用,从而能够调用同名方法的 ?
在前面的"示例代码"中,只有在创建 InvocationHandler 接口的实现类对象时,才传入 RealSubject 对象,而 InvocationHandler 实例对象在创建"代理类"对象时作为参数传入,所以"代理类"对象应该是通过 InvocationHandler 实例来间接持有对 RealSubject 的引用。
给 UserService 新增一个方法 getUserName(),把生成的"代理类"字节码文件输出到硬盘上,查看生成的 .class 文件如下:
java
// 生成 .class 文件
String path = "D:/$Proxy0.class";
System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0", UserServiceImpl.class.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
java
// .class 文件内容
public final class $Proxy0 extends Proxy implements UserService {
private static Method m4;
private static Method m3;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
// 省略 equals\toString\hashCode 方法
public final User getUserById(Long var1) throws {
try {
return (User)super.h.invoke(this, m4, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String getUserName() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
// ...
m4 = Class.forName("xxx.UserService").getMethod("getUserById", Class.forName("java.lang.Long"));
// ...
m3 = Class.forName("xxx.UserService").getMethod("getUserName");
// ...
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
从"代理类"的 .class 文件中可以看出:
1、"代理类"是 Proxy 的子类、实现了被代理的接口 UserService,并通过反射实现了接口中所有方法;
2、在调用方法时,实际上调用了 InvocationHandler 对象的 invoke 方法,在 invoke() 方法中调用了 InvocationHandler 持有的 RealSubject 同名方法
因此,只需要在 invoke 方法中实现额外逻辑,就可以实现对 RealSubject 对象方法的控制访问。
总结
动态代理中各个类之间的关系如下图所示:

在上面的UML图中:
- WeakCache 的 get() 方法会取出 map 中内层的 Supplier,调用 Supplier 的 get() 方法
- 该 Supplier 的具体实现类是 WeakCache#Factory,它的 get() 方法又会调用 WeakCache.valueFactory 属性的 apply() 方法
- WeakCache.valueFactory 的具体实现是 Proxy#ProxyClassFactory,该实例是在 Proxy 初始化 proxyClassCache 属性时作为参数传入的
- Proxy#ProxyClassFactory 的 get 方法生成代理类的字节码,并载入到JVM中,然后返回 Class 对象
整个调用时序如下图所示:

动态代理的注意点:
- 生成的代理类为 public final,不能被继承
- 类名格式是"$ProxyN",N表示 Proxy 第N次生成代理类
- 对于同一组接口(接口相同、顺序相同),不会重复创建动态代理类,而是返回一个先前已经创建并缓存了的代理类对象,提高了效率
- java.lang.Object 中有三个方法也同样会被分派到handler的 invoke 方法执行,它们是 hashCode,equals 和 toString
- 因为是在运行时创建 .class 字节码和 class 对象,所以性能要比静态代理要差
- 为什么只能实现接口的动态代理?因为传入的目标代理类是一个 class 数组,java 不支持多继承,只支持多重实现,所以只能代理接口。