知识回顾
上篇文章初识AOP中,了解到为什么要用代理,静态代理和动态代理的区别,其中动态代理我们又分别讲到了JDK的动态代理和CGLIB的动态代理,本篇文章我们将深入了解JDK中的动态代理是如何实现的。
定义一个IHello的接口和一个Hello的实现类如下
package seven.com.seven.aop;
public interface IHello {
void say();
}
package seven.com.seven.aop;
public class Hello implements IHello {
@Override
public void say() {
System.out.println("hello word");
}
}
JDK的动态代理类如下
package seven.com.seven.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicJDKProxy implements InvocationHandler {
/**
* 被代理对象
*/
private Object target;
/**
* 通过JDK的Proxy动态创建代理对象
* @param target
* @return
*/
public Object getProxy(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long star = System.currentTimeMillis();
Object result = method.invoke(target, args);
long end = System.currentTimeMillis();
System.out.println(String.format("method cost %s", (end - star)));
return result;
}
}
package seven.com;
import seven.com.seven.aop.DynamicJDKProxy;
import seven.com.seven.aop.Hello;
import seven.com.seven.aop.IHello;
public class App {
public static void main(String[] args) {
/**
* 通过此语句可以把动态生成的class文件保存到磁盘,然后通过 反编译工具得到代码
*/
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Hello hello = new Hello();
IHello proxy = (IHello) new DynamicJDKProxy().getProxy(hello);
proxy.say();
}
}
分析代理文件
通过上面把参数sun.misc.ProxyGenerator.saveGeneratedFiles设置为true,可以把代理文件生成到磁盘中,我们可以看到在当前目录下可以看到com/sun/proxy文件夹中有一个$Proxy0.class的文件,反编译看下源码如下
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import seven.com.seven.aop.IHello;
public final class $Proxy0 extends Proxy implements IHello {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
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);
}
}
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);
}
}
public final void say() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
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);
}
}
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("seven.com.seven.aop.IHello").getMethod("say");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
小结
- 生成的动态代理类的命名为com.sun.proxy.Proxy+一个数字
- 生成的动态代理类继承Proxy,且实现其被代理对象所实现的接口
-
生成动态代理类中方法的执行,最终是执行其父类Proxy中的h字段(InvocationHandler对象)的invoke方法
JDK的动态代理
InvocationHandler
package java.lang.reflect; public interface InvocationHandler { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable; }
Proxy
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<?> 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; } }); } return cons.newInstance(new Object[]{h}); } }
通过源码可以看出是通过Class<?> cl = getProxyClass0(loader, intfs);
这句代码来获取代理类的,其实最终是调用ProxyClassFactory的apply来动态生成代理类的字节码的,如下private static final class ProxyClassFactory implements BiFunction<ClassLoader, Class<?>[], 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<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length); for (Class<?> intf : interfaces) { /* * Verify that the class loader resolves the name of this * interface to the same Class object. */ 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"); } /* * Verify that the Class object actually represents an * interface. */ if (!interfaceClass.isInterface()) { throw new IllegalArgumentException( interfaceClass.getName() + " is not an interface"); } /* * Verify that this interface is not a duplicate. */ if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) { throw new IllegalArgumentException( "repeated interface: " + interfaceClass.getName()); } } String proxyPkg = null; // package to define proxy class in int accessFlags = Modifier.PUBLIC | Modifier.FINAL; /* * Record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. Verify that * all non-public proxy interfaces are in the same 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) { // 用com.sun.proxy这个包名 proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } /* * 根据规则生成 代理文件的类名,com.sun.proxy.$Proxy+数字 */ long num = nextUniqueNumber.getAndIncrement(); String proxyName = proxyPkg + proxyClassNamePrefix + num; /* * 生成代理类的字节码 */ byte[] proxyClassFile = ProxyGenerator.generateProxyClass( proxyName, interfaces, accessFlags); try { return defineClass0(loader, proxyName, proxyClassFile, 0, proxyClassFile.length); } catch (ClassFormatError e) { throw new IllegalArgumentException(e.toString()); } } }
####总结
1. 动态代理JDK根据代理文件的类名和实现的接口,动态的生成字节码,然后加载到JVM中的,最后通过反射创建代理类对象
2. JDK的动态代理是根据接口来生成字节码的,所以代理对象必须实现接口,非接口对象不能代理
3. 代理类的最终执行是通过InvocationHandler的invoke来最终执行的,可以在这里做一些前置或者后置的拦截,以此来增强被代理对象的功能
>微信公众号:宋坤明
下面的是我的公众号二维码图片,欢迎关注。
![图注:宋坤明公众号](https://mmbiz.qpic.cn/mmbiz_jpg/5DXUjepfcKRBbZzRKpcVaHZARuA0bhZFMfC3EWiaLOj8qRSiaVjibl4OUibVZOo0AY8XFtuzibZdjAksafUp2CiafvxA/0?wx_fmt=jpeg)
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦