JAVA动态代理是JAVA7的重要特性,其主要功能是通过proxy对象实现动态接口实现。
public class PracticeInvocationHandler implements InvocationHandler{
private Object receiverObject;
public PracticeinvocationHandler(Object object) {
this.receiverObject = object;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("调用方法" + method.getName());
System.out.println("参数列表" + Arrays.deepToString(args));
return method.invoke(receiverObject, args);
}
}
public interface PracticeObject extends Comparable{
}
public class PracticeObjectImpl implements PracticeObject {
public int compareTo(Object o) {
return 0;
}
}
public class PracticeProxy {
public static void main(String[] args) {
String str = "Hello World";
PracticeInvocationHandler handler = new PracticeInvocationHandler(str);
ClassLoader loader = PracticeObject.class.getClassLoader();
PracticeObject obj = (PracticeObject) Proxy.newProxyInstance(loader, new Class[]{PracticeObject.class}, handler);
obj.compareTo("Good");
}
}
接下来我们使用Debug进行源码深入剖析,Into Proxy.newProxyInstance之后抛开错误检验相关进入第一个重要的方法
/*
* Look up or generate the designated proxy class.
*/
Class cl = getProxyClass(loader, interfaces);
<span style="font-family: Arial, Helvetica, sans-serif; white-space: normal; background-color: rgb(255, 255, 255); ">
</span>
<span style="font-family: Arial, Helvetica, sans-serif; white-space: normal; background-color: rgb(255, 255, 255); ">深入此方法,一个for循环中进行错误率的检测之后,我们可以看到</span>
<span style="font-family: Arial, Helvetica, sans-serif; white-space: normal; background-color: rgb(255, 255, 255); ">/*
<span style="white-space:pre"> </span> * Using string representations of the proxy interfaces as
<span style="white-space:pre"> </span> * keys in the proxy class cache (instead of their Class
<span style="white-space:pre"> </span> * objects) is sufficient because we require the proxy
<span style="white-space:pre"> </span> * interfaces to be resolvable by name through the supplied
<span style="white-space:pre"> </span> * class loader, and it has the advantage that using a string
<span style="white-space:pre"> </span> * representation of a class makes for an implicit weak
<span style="white-space:pre"> </span> * reference to the class.
*/
</span>
<span style="font-family:Arial, Helvetica, sans-serif;"><span style="white-space: normal; "><span style="color:#cc6600;font-weight: bold; ">用字符串表示代理接口 作为 代理缓存的 标识(而不是类的对象) 就已经足够,因为我们仅仅需要代理接口可以被类加载器识别。这种方式有一个有点,这只是一个弱引用</span></span></span><pre name="code" class="java">/*
* Find or create the proxy class cache for the class loader.
*/
Map cache;
synchronized (loaderToCache) {
cache = (Map) loaderToCache.get(loader);
if (cache == null) {
cache = new HashMap();
loaderToCache.put(loader, cache);
}
/*
* This mapping will remain valid for the duration of this
* method, without further synchronization, because the mapping
* will only be removed if the class loader becomes unreachable.
*/
}
此处的loaderToCache是一个WeakHashMap(线程安全),在这将类装载器装入并对应生成一个空HashMap
Spring通过CgLib实现 动态代理(另外一种实现动态代理方式)
CgLib是一个开源动态代理框架,基于ASM实现动态代理。相较JDK Proxy技术,编译速度相对慢(Spring 启动慢的原因之一),执行速度较快。可以通过缓存加速编译~