无论是静态代理,还是Cglib动态代理,都比较容易理解,本文就通过进入源码的方式来看看JDK动态代理的实现原理进行分析
要了解动态代理的可以参考另一篇文章,有详细介绍,这里仅仅对JDK动态代理做源码分析。
一文理解JDK静态代理、JDK动态代理、Cglib动态代理
源码分析共识
为了避免影响分析,一些没用的代码已经被清理
JDK动态代理源码分析
平时我们是这样使用动态代理的,主要方法在Proxy.newProxyInstance(classLoader, userService.getClass().getInterfaces(), proxyHandler)
public static void main(String[] args) {
// 保存创建的代理类,默认保存项目根目录下的com.sun.proxy.$Proxy0.class
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 代理的对象,可以动态切换代理
RealSubject userService = new RealSubject();
// 代理的具体实现
ProxyHandler proxyHandler = new ProxyHandler(userService);
ClassLoader classLoader = proxyHandler.getClass().getClassLoader();
// note 根据指定参数动态创建代理对象
Subject proxyObject = (Subject) Proxy.newProxyInstance(classLoader,
userService.getClass().getInterfaces(), proxyHandler);
proxyObject.visit();
}
setup 1:进入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);
}
//【代理类生成的主要方法】查询在(如果缓存中有则在缓存获取)或生成指定代理类的class代理对象
Class<?> cl = getProxyClass0(loader, intfs);
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
// 获取代理类的构造函数,constructorParams为构造参数
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类
// 创建的代理类中会生成具有相同接口的对象,然后调用代理类方法的时候转发到InvocationHandler的invoke方法
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException | InstantiationException e) {
...
} catch (InvocationTargetException e) {
...
} catch (NoSuchMethodException e) {
...
}
}
可以看到,主要是最后的返回值getProxyClass0(loader, intfs)
,我们进入详细看下
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 代理接口数限制
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 获取代理类有两种方式:
// 1.给定的类加载器loader实现给定的接口定义interfaces的代理类存在,返回缓存
// 2.不存在通过ProxyClassFactory创建代理类
return proxyClassCache.get(loader, interfaces);
}
这里实际上是一个缓存对象,如果有,则直接在缓存中返回,如果没有则通过ProxyClassFactory
创建代理类,看下这个proxyClassCache
字段的定义
private static final WeakCache<ClassLoader, Class<?>[], Class<?>>
proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
ProxyClassFactory是Proxy的一个静态私有类
// 根据类加载器和接口列表生成、定义和返回一个代理类。
private static final class ProxyClassFactory
implements BiFunction<ClassLoader, Class<?>[], Class<?>> {
// 所有代理类的命名前缀
private static final String proxyClassNamePrefix = "$Proxy";
// 使用一个唯一的number作为proxy class标识
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) {
// 确认类加载器解析了这个名字的接口到相同的class对象
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");
}
// 确认代理的Class是接口,这也是JDK动态代理的劣势
if (!interfaceClass.isInterface()) {
throw new IllegalArgumentException(
interfaceClass.getName() + " is not an interface");
}
// 校验接口是否有重复
if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
throw new IllegalArgumentException(
"repeated interface: " + interfaceClass.getName());
}
}
String proxyPkg = null; // 定义proxy class所在的package
int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
// 验证所有non-public的proxy interfaces都在同一个package
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");
}
}
}
if (proxyPkg == null) {
// 如果没有non-public的interfaces,默认使用包都为com.sun.proxy
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
* 选择要生成的代理类的名称
* 大致为:com.sun.proxy.$Proxy1
*/
long num = nextUniqueNumber.getAndIncrement();
String proxyName = proxyPkg + proxyClassNamePrefix + num;
// 生成特殊的proxy class
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 把代理类加载到JVM中,至此动态代理过程基本结束了
return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
...
}
}
}
这里是确定了代理类的名称,然后使用ProxyGenerator.generateProxyClass()
方法生成代理类的字节流,接下来我们看看这个方法的内部实现
sun.misc.ProxyGenerator在sun包之下,没有开源,可以通过反编译的形式获取;或者使用openJDK中的源码
// 生成一个代理类文件并返回字节流
private byte[] generateClassFile() {
// 接下去的步骤基本都是构建一个class文件
// Step 1: 添加从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);
}
try {
// Step 2: 添加构造方法,入参为InvocationHandler
methods.add(generateConstructor());
for (List<ProxyMethod> sigmethods : proxyMethods.values()) {
for (ProxyMethod pm : sigmethods) {
// 添加静态字段,大致为:private static Method m1;
fields.add(new FieldInfo(pm.methodFieldName,
"Ljava/lang/reflect/Method;",
ACC_PRIVATE | ACC_STATIC));
// 生成代理方法的MethodInfo并添加到methods
methods.add(pm.generateMethod());
}
}
// 添加静态初始化代码块,结果大致如下:
// static {
// try {
// m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
// m2 = Class.forName("java.lang.Object").getMethod("toString");
// m3 = Class.forName("com.siqi.proxy.jdk_dynamic_proxy.Subject").getMethod("visit");
// m0 = Class.forName("java.lang.Object").getMethod("hashCode");
// } catch (NoSuchMethodException var2) {
// throw new NoSuchMethodError(var2.getMessage());
// } catch (ClassNotFoundException var3) {
// throw new NoClassDefFoundError(var3.getMessage());
// }
// }
methods.add(generateStaticInitializer());
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
if (methods.size() > 65535) {
throw new IllegalArgumentException("method limit exceeded");
}
if (fields.size() > 65535) {
throw new IllegalArgumentException("field limit exceeded");
}
cp.getClass(dotToSlash(className));
cp.getClass(superclassName);
for (Class<?> intf: interfaces) {
cp.getClass(dotToSlash(intf.getName()));
}
cp.setReadOnly();
// Step 3: 生成最终文件
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
try {
dout.writeInt(0xCAFEBABE);
dout.writeShort(CLASSFILE_MINOR_VERSION);
dout.writeShort(CLASSFILE_MAJOR_VERSION);
cp.write(dout);
dout.writeShort(accessFlags);
dout.writeShort(cp.getClass(dotToSlash(className)));
dout.writeShort(cp.getClass(superclassName));
dout.writeShort(interfaces.length);
for (Class<?> intf : interfaces) {
dout.writeShort(cp.getClass(
dotToSlash(intf.getName())));
}
dout.writeShort(fields.size());
for (FieldInfo f : fields) {
f.write(dout);
}
dout.writeShort(methods.size());
for (MethodInfo m : methods) {
m.write(dout);
}
dout.writeShort(0);
} catch (IOException e) {
throw new InternalError("unexpected I/O Exception", e);
}
// 返回创建的class文件字节流
return bout.toByteArray();
}
至此源码基本就分析完成了,接下来我们看看最终生成的class文件:
package com.sun.proxy;
import com.siqi.proxy.jdk_dynamic_proxy.Subject;
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 var1) throws {
super(var1);
}
// 代理了equals
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
// 打理了toString
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
// 这里就是我们的业务接口visit
public final void visit() throws {
try {
// 【重要】这句话就是调用了InvocationHandler对象的invoke
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
// 代理了hashCode
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
// 使用静态代码块初始化所有Method字段
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("com.siqi.proxy.jdk_dynamic_proxy.Subject").getMethod("visit");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
基本上和我们源码分析的过程一致
总结
JDK动态代理中,主要用到三个类:Proxy
、私有内部类ProxyClassFactory
、代理生成类ProxyGenerator
,通过对接口的clone一份,实现一个拥有同样接口的代理类,调用的时候再转发到IvocationHandler的类中,这个类中持有对RealSubject的引用,在invoke方法实现代理,对实际方法进行调用super.h.invoke(this, m3, (Object[])null);
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/17884.html