JDK动态代理深入剖析
1 基于接口的代理模式
什么是代理?
简单来说,代理是指一个对象代替另一个对象去做某些事情。
例如,对于每个程序员来说,他都有编程的能力:
interface Programmable {
void developSoftware();
}
对于Java
程序员,他会编写Java
代码:
class JavaProgrammer implements Programmable {
@Override
public void developSoftware() {
System.out.println("编写Java代码");
}
}
对于JavaScript
程序员,他会编写JavaScript
代码:
class JavaScriptProgrammer implements Programmable {
@Override
public void developSoftware() {
System.out.println("编写JavaScript代码");
}
}
……
为了完成一个商业软件,需要各种程序员共同协作。
因此,互联网公司出现了:
class ITCompany implements Programmable {
private List<Programmable> programmers = new LinkedList<>();
public void recruitProgrammer(Programmable programmer) {
programmers.add(programmer);
}
@Override
public void developSoftware() {
designProduct();
programmers.forEach(Programmable::developSoftware);
operate();
}
public void designProduct() {
System.out.println("产品设计");
}
public void operate() {
System.out.println("上线运营");
}
}
此时,互联网公司对程序员进行了代理,并通过提供额外的功能,完善了善软件开发流程:产品设计 → 编写代码 → 上线运营等。
ITCompany company = new ITCompany();
company.recruitProgrammer(new JavaProgrammer());
company.recruitProgrammer(new JavaScriptProgrammer());
company.developSoftware();
输出如下:
产品设计
编写Java代码
编写JavaScript代码
上线运营
总结类图如下:
以上方式被称为静态代理模式,步骤如下:
- 实现被代理接口。
- 保存被代理对象。
- 自定义增强方法。
- 实现被代理的方法。
2 JDK动态代理-Proxy
静态代理有一个明显的局限性,那就是它只能固定代理某一类接口。如果需要代理其他接口,就必须重新编写一个代理类。
java.lang.reflect.Proxy
提供了一系列创建动态代理类和实例的静态方法。
例如,为了创建Programmable
接口的代理类,可以按如下方式:
// 1、自定义增强方法
InvocationHandler handler = new MyInvocationHandler();
// 2、创建代理类
Class<?> proxyClass = Proxy.getProxyClass(Programmable.class.getClassLoader(), Programmable.class);
// 3、创建代理对象
Programmable p = (Programmable) proxyClass.getConstructor(InvocationHandler.class).newInstance(handler);
或者:
Programmable p = (Programmable) Proxy.newProxyInstance(Programmable.class.getClassLoader(),
new Class<?>[] { Programmable.class },
handler);
很明显,第二种方式更加简便(推荐使用)。它其实是对第一种方式进行了封装,并且做了许多安全处理:
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<?> cl = getProxyClass0(loader, intfs);
// 3、实例化代理对象
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) {
}
}
我们可以发现,Proxy
创建代理对象的核心步骤有两步:
- 创建代理类。
- 实例化代理对象。
2.1 创建代理类
创建代理类核心方法为java.lang.reflect.Proxy#getProxyClass0
:
private static Class<?> getProxyClass0(ClassLoader loader, Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
return proxyClassCache.get(loader, interfaces);
}
-
java.lang.reflect.Proxy#proxyClassCache
成员变量中会缓存已创建的代理类(key: 类加载器, parameter: 接口对象数组, value: 代理类对象)。private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
-
在
WeakCache#get()
方法中会调用到如下代码:V value = supplier.get();
,进而执行valueFactory.apply(key, parameter)
。其中valueFactory
为ProxyClassFactory
对象。
ProxyClassFactory#apply()
方法中才会真正创建代理类:
public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
// 1、校验interfaces
Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
for (Class<?> intf : interfaces) {
// 1.1、接口?重复?类加载器可访问?
}
String proxyPkg = null; // package to define proxy class in
for (Class<?> intf : interfaces) {
// 1.2、non-public接口是否在同一个包下
}
// 2、生成包名
if (proxyPkg == null) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num; // 包名 + $Proxy + 递增数字
// 3、生成代理类class文件
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces, accessFlags);
try {
// 4、动态加载代理类
return defineClass0(loader, proxyName,proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
}
}
核心在于ProxyGenerator#generateProxyClass()
:
public static byte[] generateProxyClass(final String proxyName, Class<?>[] interfaces, int accessFlags) {
ProxyGenerator proxyGenerator = new ProxyGenerator(proxyName, interfaces, accessFlags);
// 生成class文件
final byte[] clzBytes = proxyGenerator.generateClassFile();
if (saveGeneratedFiles) {
// 保存class文件
}
return clzBytes;
}
proxyGenerator#generateClassFile()
中生成.class
文件:
private byte[] generateClassFile() {
// 1、添加Object中的方法到proxyMethods缓存:hashCode()、equals()、toString()
this.addProxyMethod(hashCodeMethod, Object.class);
this.addProxyMethod(equalsMethod, Object.class);
this.addProxyMethod(toStringMethod, Object.class);
// 2、添加interfaces中的方法到proxyMethods缓存
Class[] interfaces = this.interfaces;
int interfacesLength = interfaces.length;
int i;
Class interfaceClz;
for(i = 0; i < interfacesLength; ++i) {
interfaceClz = interfaces[i];
Method[] methods = interfaceClz.getMethods();
int methodsLength = methods.length;
for(int index = 0; index < methodsLength; ++index) {
Method m = methods[index];
this.addProxyMethod(m, interfaceClz);
}
}
try {
// 3、生成构造函数(形参为:InvocationHandler),添加到methods缓存
this.methods.add(this.generateConstructor());
proxyMethodsIterator = this.proxyMethods.values().iterator();
while(proxyMethodsIterator.hasNext()) {
proxyMethodList = (List)proxyMethodsIterator.next();
iterator = proxyMethodList.iterator();
while(iterator.hasNext()) {
ProxyGenerator.ProxyMethod proxyMethod = (ProxyGenerator.ProxyMethod)iterator.next();
// 4、生成代理方法成员变量,变量名为m[n],类型为Method,添加到fields缓存
this.fields.add(new ProxyGenerator.FieldInfo(proxyMethod.methodFieldName, "Ljava/lang/reflect/Method;", 10));
/* 5、生成代理方法,添加到methods缓存。
代理方法执行逻辑:
创建变量:InvocationHandler对象/当前Method对象/方法原有形参,
执行InvocationHandler.invoke()方法
*/
this.methods.add(proxyMethod.generateMethod());
}
}
// 6、生成静态初始化方法(没有形参)
this.methods.add(this.generateStaticInitializer());
} catch (IOException interfaces0) {}
if (this.methods.size() > 65535) {} else if (this.fields.size() > 65535) {
} else {
// 7、生成类名
this.cp.getClass(dotToSlash(this.className));
// 8、继承父类:Proxy
this.cp.getClass("java/lang/reflect/Proxy");
// 9、实现所有接口
interfaces = this.interfaces;
interfacesLength = interfaces.length;
for(i = 0; i < interfacesLength; ++i) {
interfaceClz = interfaces[i];
this.cp.getClass(dotToSlash(interfaceClz.getName()));
}
// 10、写出到字节流
this.cp.setReadOnly();
ByteArrayOutputStream byteArrOutput = new ByteArrayOutputStream();
DataOutputStream dataOutput = new DataOutputStream(byteArrOutput);
try {
dataOutput.writeInt(-889275714);
dataOutput.writeShort(0);
dataOutput.writeShort(49);
this.cp.write(dataOutput);
// 访问修饰符
dataOutput.writeShort(this.accessFlags);
// 类名
dataOutput.writeShort(this.cp.getClass(dotToSlash(this.className)));
// 父类:Proxy
dataOutput.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));
// 接口
dataOutput.writeShort(this.interfaces.length);
Class[] interfacesArr = this.interfaces;
int interfacesArrLen = interfacesArr.length;
for(int i = 0; i < interfacesArrLen; ++i) {
Class interfaceClz = interfacesArr[i];
dataOutput.writeShort(this.cp.getClass(dotToSlash(interfaceClz.getName())));
}
// 成员变量:即代理方法名-Method
dataOutput.writeShort(this.fields.size());
iterator = this.fields.iterator();
while(iterator.hasNext()) {
ProxyGenerator.FieldInfo f = (ProxyGenerator.FieldInfo)iterator.next();
f.write(dataOutput);
}
// 代理方法:重新编写执行逻辑后的方法
dataOutput.writeShort(this.methods.size());
iterator = this.methods.iterator();
while(iterator.hasNext()) {
ProxyGenerator.MethodInfo m = (ProxyGenerator.MethodInfo)iterator.next();
m.write(dataOutput);
}
dataOutput.writeShort(0);
return byteArrOutput.toByteArray();
} catch (IOException var9) {
}
}
}
因此,java.lang.reflect.Proxy#getProxyClass0
的核心作用如下:
- 如果缓存中,由类加载器
loader
加载,并且实现给定接口interfaces
的代理类已经存在,会直接返回该代理类。 - 如果代理类不存在,会使用
ProxyClassFactory
创建新的代理类。
例如,对于某些接口:
public interface IT1 {
void fun1();
}
public interface IT2 {
Object fun2(Object[] args);
}
生成代理类的伪代码如下:
package com.sun.proxy|non-public接口所在包
[public] final class $Proxy[n]
extends Proxy
implements IT1, IT2 {
protected InvocationHandler h; // Proxy类中
private static Method m0; // hashCode
private static Method m1; // equals
private static Method m2; // toString
private static Method m3; // fun1
private static Method m4; // fun2
public void hashCode() {
InvocationHandler handler = this.h;
Method m = this.mo;
handler.invoke(this, m, null);
}
public void equals(Object obj) {
InvocationHandler handler = this.h;
Method m = this.m1;
handler.invoke(this, m, obj);
}
public void toString() {
InvocationHandler handler = this.h;
Method m = this.m2;
handler.invoke(this, m, null);
}
public void fun1() {
InvocationHandler handler = this.h;
Method m = this.m3;
handler.invoke(this, m, null);
}
public Object fun2(Object[] args) {
InvocationHandler handler = this.h;
Method m = this.m4;
Object rs = handler.invoke(this, m, args);
return rs;
}
}
- 如果接口全为
public
,则代理类修饰符为public final
。此时类名为com.sun.proxy.$Proxy[n]
。 - 如果接口中存在
non-public
接口,且全位于同一个包下,则代理类修饰符为final
。此时类名为non-public接口所在包.$Proxy[n]
。 - 需要注意的是,
Object
对象中只有hashCode()
、equals()
和toString()
这三个方法会被重写。 - 动态生成的代理类修饰符为
final
,这意味着它不能被继承。
例如,我们通过以下方式生成代理类,并打印出相关数据:
Real real = new Real();
Object proxyInstance = Proxy.newProxyInstance(ProxyDemo.class.getClassLoader(),
new Class[]{IT1.class, IT2.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("proxy method: " + method.getName());
return method.invoke(real, args);
}
});
// 获取当前代理类的属性
System.out.println("代理类成员变量:");
Field[] fields = proxyInstance.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
StringBuilder sb = new StringBuilder();
Field field = fields[i];
// 修饰符
int modifiers = field.getModifiers();
sb.append(Modifier.toString(modifiers)).append(" ");
field.setAccessible(true);
// 成员变量类型&变量名
sb.append(field.getType().getName()).append(" ").append(field.getName()).append(":");
Method m = (Method) field.get(Method.class);
m.setAccessible(true);
// 方法名
sb.append(m.getName());
System.out.println(sb.toString());
}
System.out.println("Proxy类成员变量:");
Field[] superFields = proxyInstance.getClass().getSuperclass().getDeclaredFields();
for (int i = 0; i < superFields.length; i++) {
StringBuilder sb = new StringBuilder();
Field field = superFields[i];
// 修饰符
int modifiers = field.getModifiers();
sb.append(Modifier.toString(modifiers)).append(" ");
field.setAccessible(true);
// 成员变量类型&变量名
sb.append(field.getType().getName()).append(" ").append(field.getName());
System.out.println(sb.toString());
}
System.out.println("代理类方法:");
Method[] methods = proxyInstance.getClass().getMethods();
for (int i = 0; i < methods.length; i++) {
StringBuilder sb = new StringBuilder();
Method method = methods[i];
int modifiers = method.getModifiers();
sb.append(Modifier.toString(modifiers)).append(" ");
sb.append(method.getReturnType().getName()).append(" ").append(method.getName());
System.out.println(sb.toString());
}
System.out.println("代理类构造函数:");
Constructor<?>[] constructors = proxyInstance.getClass().getConstructors();
for (int i = 0; i < constructors.length; i++) {
StringBuilder sb = new StringBuilder();
Constructor constructor = constructors[i];
int modifiers = constructor.getModifiers();
sb.append(Modifier.toString(modifiers)).append(" ");
sb.append(constructor.getName()).append("(");
Class[] parameterTypes = constructor.getParameterTypes();
for (int i1 = 0; i1 < parameterTypes.length; i1++) {
sb.append(parameterTypes[i1].getName());
if (i1 < parameterTypes.length - 1) {
sb.append(",");
}
}
sb.append(")");
System.out.println(sb.toString());
}
打印结果如下:
代理类成员变量:
private static java.lang.reflect.Method m1:equals
private static java.lang.reflect.Method m3:fun1
private static java.lang.reflect.Method m2:toString
private static java.lang.reflect.Method m4:fun2
private static java.lang.reflect.Method m0:hashCode
Proxy父类成员变量:
private static final long serialVersionUID
private static final [Ljava.lang.Class; constructorParams
private static final java.lang.reflect.WeakCache proxyClassCache
protected java.lang.reflect.InvocationHandler h
private static final java.lang.Object key0
代理类方法:
public final boolean equals
public final java.lang.String toString
public final int hashCode
public final void fun1
public final java.lang.Object fun2
public static boolean isProxyClass
public static java.lang.reflect.InvocationHandler getInvocationHandler
public static transient java.lang.Class getProxyClass
public static java.lang.Object newProxyInstance
public final void wait
public final void wait
public final native void wait
public final native java.lang.Class getClass
public final native void notify
public final native void notifyAll
代理类构造函数:
public com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
2.2 实例化代理类对象
有了以上的基础,我们应该能很容易理解接下来的操作了。
// 1、根据类型获取构造函数:形参为InvocationHandler
final Constructor<?> cons = cl.getConstructor(constructorParams);
// 2、通过构造函数实例化代理对象,并返回
final InvocationHandler ih = h;
return cons.newInstance(new Object[]{h});
2.3 总结
使用JDK-动态代理Proxy
的方式如下:
- 实现
InvocationHandler
接口,其中invoke()
方法为代理类实际执行的方法。 - 调用
Proxy.newProxyInstance()
方法,传入类加载器、代理接口数组和InvocationHandler
对象。
最终生成代理类的类图如下:
3 实例
3.1 Spring
中的JDK动态代理
Spring使用org.springframework.aop.framework.ProxyFactoryBean
进行AOP动态代理:
public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.info("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}
其最终会调用org.springframework.aop.framework.JdkDynamicAopProxy#getProxy(java.lang.ClassLoader)
方法,进行JDK动态代理:
public Object getProxy(@Nullable ClassLoader classLoader) {
if (logger.isTraceEnabled()) {
logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
}
return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);
}
JdkDynamicAopProxy
是Spring中JDK动态代理的核心类,它既作为动态代理的工具类,又作为InvocationHandler
实现类定义了代理方法执行逻辑:
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
其中实现的invoke()
方法如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
MethodInvocation invocation =
new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
3.2 Mybatis
中的JDK动态代理
org.apache.ibatis.session.SqlSession#getMapper
可以获取动态生成的mapper
实例:
<T> T getMapper(Class<T> type);
其底层会调用org.apache.ibatis.binding.MapperRegistry#getMapper
:
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
通过org.apache.ibatis.binding.MapperProxyFactory#newInstance(org.apache.ibatis.session.SqlSession)
最终生成代理类:
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
其中org.apache.ibatis.binding.MapperProxy
是InvocationHandler
实现类,其invoke()
方法如下:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
try {
return MapUtil.computeIfAbsent(methodCache, method, m -> {
if (m.isDefault()) {
try {
if (privateLookupInMethod == null) {
return new DefaultMethodInvoker(getMethodHandleJava8(method));
} else {
return new DefaultMethodInvoker(getMethodHandleJava9(method));
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException
| NoSuchMethodException e) {
throw new RuntimeException(e);
}
} else {
return new PlainMethodInvoker(new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()));
}
});
} catch (RuntimeException re) {
Throwable cause = re.getCause();
throw cause == null ? re : cause;
}
}
private MethodHandle getMethodHandleJava9(Method method)
throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
final Class<?> declaringClass = method.getDeclaringClass();
return ((Lookup) privateLookupInMethod.invoke(null, declaringClass, MethodHandles.lookup())).findSpecial(
declaringClass, method.getName(), MethodType.methodType(method.getReturnType(), method.getParameterTypes()),
declaringClass);
}
- 对于
Object
方法,它不会进行代理。 - 对于非
Object
方法,会找到对应的Method
对象,然后传入参数进行调用。