在java中,动态代理分为两类:java
而今天我要讲的是前者,基于接口的动态代理。动态代理在框架中的应用很是普遍,理解了动态代理,对spring,mybatis等经常使用框架的源码阅读也很是有帮助。这篇文章的由来也是由于肺炎(各位必定不用乱跑阿,出门也要记得带口罩,这个真的很重要!!!),只能在家看mybatis源码,看到sqlSession.getMapper(Class class)
方法时,由于源码中用到了JDK动态代理,因此决定深挖一下JDK动态代理的实现。spring
看完这篇文章,你能收获的知识:sql
invoke()
方法?invoke(Object proxy, Method method, Object[] args)
中的method参数是如何知道咱们执行的是哪一个方法。后面的全部解析都会基于这个例子进行讲解缓存
由于JDK动态代理是基于接口的,全部咱们首先要建立一个接口mybatis
public interface Hello {
void sayHello();
}
复制代码
而后咱们给这个接口一个实现类,这个实现类并非必须的,mybatis中就是直接利用接口,而没有这个实现类,这里是为了更加易于理解。app
public class Amy implements Hello{
private String name;
public Amy(String name) {
this.name = name;
}
public void sayHello() {
System.out.println(name + " say hello");
}
}
复制代码
接着咱们建立一个代理类(这个代理类跟下文源码分析中JDK生成的代理类并非同一回事,请务必分清楚,以避免理解出错),JDK动态代理规定代理类必须实现InvocationHandler接口框架
public class ProxyHello implements InvocationHandler {
private Hello hello;
public ProxyHello(Hello hello) {
this.hello = hello;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before say hello");
method.invoke(hello, args);
System.out.println("after say hello");
return null;
}
}
复制代码
最后咱们写一个测试类,建立一个代理对象,执行sayHello()
方法,看看输出的结果ide
public class Test {
public static void main(String[] args) {
Amy amy = new Amy("Amy");
ProxyHello proxyHello = new ProxyHello(amy);
Hello helloProxy = (Hello) Proxy.newProxyInstance(
Thread.currentThread().getContextClassLoader(),
new Class[]{Hello.class},
proxyHello);
helloProxy.sayHello();
}
}
复制代码
最后输出的结果函数
经过输出结果能够知道,实际上执行的是代理对象里面的invoke()方法。源码分析
经过上面的例子能够知道,建立代理对象是经过Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
进行建立的,接收三个参数
AppClassLoader
Hello.class
,也就是咱们建立的接口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);
}
// 获取建立的代理类的构造函数,以后咱们会反编译看一下代理类的实现
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) {
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);
}
}
复制代码
getProxyClass0()
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
// 接口数量不能大于65535个,通常都用不了那么多
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
// 从缓冲中获取代理类,若是缓存中不存在再经过ProxyClassFactory建立
// 缓存是经过弱引用来缓存,弱引用很适合用来作缓存
return proxyClassCache.get(loader, interfaces);
}
复制代码
proxyClassCache.get()
public V get(K key, P parameter) {
Objects.requireNonNull(parameter);
expungeStaleEntries();
// 建立一个以classloader为引用的缓存键
Object cacheKey = CacheKey.valueOf(key, refQueue);
// map中有二级缓存
// 第一级缓存:经过上面建立的缓存键获取对应的经过该类加载器加载的
// 全部代理类,也就是第二级缓存的Map
// 第二级缓存:以接口建立的虚引用为键,对应接口的代理类的供应商为值
// 这条语句就是获取第二级缓存
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;
}
}
// 根据接口建立第二级缓存的键
Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
// 从第二级缓存中获取建立代理类的供应商
Supplier<V> supplier = valuesMap.get(subKey);
// Factory是实现了Supplier接口的工厂类
Factory factory = null;
while (true) {
if (supplier != null) {
// 若是供应商存在,那么直接从供应商获取代理类
V value = supplier.get();
if (value != null) {
// 获取到代理类,直接返回
return value;
}
}
// 建立一个新的供应商
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);
}
}
}
}
复制代码
咱们真正建立和获取代理类的方法就是supplier.get()
。
一般状况下,第一次循环都是获取不到代理类的,第一次循环都是建立一个供应商,而后存入到缓存中,第二次循环从缓存中获取到供应商,而后从供应商处获取代理类。
supplier.get()
由于supplier变量是引用了Factory类的对象,因此咱们实际要看的是Factory类的get()
方法
Factory类是WeakCache的私有内部类
private final class Factory implements Supplier<V> {
private final K key;
private final P parameter;
private final Object subKey;
private final ConcurrentMap<Object, Supplier<V>> valuesMap;
Factory(K key, P parameter, Object subKey,
ConcurrentMap<Object, Supplier<V>> valuesMap) {
this.key = key;
this.parameter = parameter;
this.subKey = subKey;
this.valuesMap = valuesMap;
}
@Override
public synchronized V get() { // serialize access
// 从新检查是否存在对应的代理类供应商
Supplier<V> supplier = valuesMap.get(subKey);
if (supplier != this) {
return null;
}
// else still us (supplier == this)
// create new value
V value = null;
try {
// 这句是重点,valueFactory是建立代理类的工厂
// 由该工厂建立一个真正的代理类
// 它是ProxyClassFactory类的实例对象
value = Objects.requireNonNull(valueFactory.apply(key, parameter));
} finally {
if (value == null) {
valuesMap.remove(subKey, this);
}
}
assert value != null;
// 为代理类建立一个虚引用
CacheValue<V> cacheValue = new CacheValue<>(value);
reverseMap.put(cacheValue, Boolean.TRUE);
// 尝试将新建立的代理类的缓存供应商替换旧的供应商
// 也就是上一个方法建立Factory类的对象
// 该方法执行必须成功
if (!valuesMap.replace(subKey, this, cacheValue)) {
throw new AssertionError("Should not reach here");
}
// 返回代理类
return value;
}
}
复制代码
valueFactory.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) {
/*
* 验证类加载器是否将此接口的名称解析为同一个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对象是不是接口
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;
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) {
// if no non-public proxy interfaces, use com.sun.proxy package
proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";
}
/*
*选择一个代理类的名称,实际就是一个递增的数字
*/
long num = nextUniqueNumber.getAndIncrement();
//代理类的全限定类名:com.sun.proxy.$Proxy0 , com.sun.proxy.$Proxy1
String proxyName = proxyPkg + proxyClassNamePrefix + num;
/*
* 生成一个代理类的class文件,也就是咱们一般建立的class类
* 该方法并非开源的。
* 咱们进去该方法能够看到一个属性saveGeneratedFiles
* 这个属性用于判断是否将建立的class文件输出到本地,
* 咱们能够在运行时设置该属性,
* 让它将生成的class文件输出,而后咱们反编译这个代理类文件
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);
try {
// 经过类文件建立Class对象,这是一个本地方法(C/C++实现),没法查看
return defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
* A ClassFormatError here means that (barring bugs in the
* proxy class generation code) there was some other
* invalid aspect of the arguments supplied to the proxy
* class creation (such as virtual machine limitations
* exceeded).
*/
throw new IllegalArgumentException(e.toString());
}
}
}
复制代码
要输出该代理类文件,咱们有两种方法:
1,咱们在运行Test
类以前,首先进行一个配置,在红色框框的部分添加这个属性-Dsun.misc.ProxyGenerator.saveGeneratedFiles=true
2,在运行代码以前,设置系统全局属性,添加红色部分的代码
运行代码,代码执行完成以后就会在main()
所在类的同级目录下看到建立了一个com.sun.proxy包,该包下面有一个$Proxy0.class
相似的class文件,这就是生成的代理类。
我没有在IDEA上找到合适的插件,网上看到的几个,不知道为何用不了,惟一一个能用的效果也很差,全部就在网上找了另一个JD-GUI,无需安装,很好用。
附上下载连接:JD-GUI
咱们直接使用这个软件打开咱们生成的代理类,以下
package com.sun.proxy;
import com.lhd.proxy.Hello;
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 Hello {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) {
try {
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void sayHello() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return ((Integer)this.h.invoke(this, m0, null)).intValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.lhd.proxy.Hello").getMethod("sayHello", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
} catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
} catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}
复制代码
经过这个代理类咱们能够知道JDK动态代理为何只能基于接口的代理,由于该代理类继承了Proxy类,而java是不支持多继承的,全部只能经过实现接口来实现代理。
咱们能够看到这个代理类实现了咱们传递进去的接口Hello
,因此代理类里面要实现该接口的方法,也就是sayHello()
方法,而这个方法的实现很是简单,其实代理类里面全部的方法都很是简单,就是执行了this.h.invoke()这个方法。
咱们分析一下这条语句:
newProxyInstance()
传递进去的ProxyHello,代理的一个构造函数也是接受这个类型的参数,咱们在newProxyInstance
方法中获取代理类的构造函数时也是获取带这个类型参数的构造函数,而后经过这个构造函数来建立代理类对象invoke()
方法当代理类对象执行sayHello()方法时,实际就是执行this.h.invoke(this, m3, null)
这个方法,也就是执行了ProxyHello类的对象的invoke()
方法,而这个方法的method参数是在最下面获取的:
m3 = Class.forName("com.lhd.proxy.Hello").getMethod("sayHello", new Class[0]);
当咱们在调用method.invoke(hello, args)
时就是调用的m3这个方法,而后指定一个执行的对象和参数,就能够执行咱们须要执行的方法了。
到目前为止,上面的五个问题就都有答案了。可是具体这个代理类的class文件是如何写入的暂时没有深究,由于没有开源,比较晦涩难懂,并且代码量庞大,就再也不深刻了。 若是有问题,能够评论区讨论。若是有错误的地方,也请多多包涵而且指正。