一、静态代理
代理设计模式,代理类和真实类有相同接口,代理类对外隐藏真实类,使用者只关系使用的接口功能,不清楚使用的是代理类还是真实类,满足功能即可。
静态代理,编译时,将接口,代理类,真实类定义好,class文件生成,按照Jvm正常的加载流程运行。
举例,接口。
public interface Base {
String hi();
}
代理类
public class ProxyBase implements Base{
RealBase real ;
public ProxyBase(RealBase real) {
super();
this.real = real;
}
@Override
public String hi() {
return real.hi();
}
}
真实类
public class RealBase implements Base {
@Override
public String hi() {
return "Real";
}
}
真实类和代理类都实现Base接口,代理类引用真实类对象,代理类方法调用真实类方法。
二、动态代理
动态代理,运行时,根据接口动态生成一个新代理类,优点是可以对所有的代理类实现的接口方法统一处理,路由到一个地方,InvocationHandler的invoke方法,通过Method识别调用的代理方法,触发真实类target的对应方法,也可以对所有方法统一加内容,比如统计打点时间。
举例,Retrofit类,利用动态代理生成interface的代理对象。
public <T> T create(final Class<T> service) {
...
return (T) Proxy.newProxyInstance(service.getClassLoader(),
new Class<?>[] { service }, new InvocationHandler() {
//该对象传入$Proxy0的构造方法中
private final Platform platform = Platform.get();
@Override
public Object invoke(Object proxy, Method method, Object... args)
throws Throwable {
...
}
});
}
Retrofit类的create方法,调用Proxy类的newProxyInstance方法,参数是类加载器ClassLoader,interface数组,InvocationHandler。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler invocationHandler)
throws IllegalArgumentException {
Exception cause;
try {
return getProxyClass(loader, interfaces)
.getConstructor(InvocationHandler.class)
.newInstance(invocationHandler);
} catch (NoSuchMethodException e) {
}
}
Class<?>[]数组只有一个interface元素,Xxx.class服务类型。
public static Class<?> getProxyClass(ClassLoader loader,
Class<?>... interfaces)
throws IllegalArgumentException {
final List<Class<?>> interfaceList =
new ArrayList<Class<?>>(interfaces.length);
...
synchronized (loader.proxyCache) {
//缓存中查找
Class<?> proxy = loader.proxyCache.get(interfaceList);
if (proxy != null) {
return proxy;
}
}
...
List<Method> methods = getMethods(interfaces);
Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
...
String baseName = commonPackageName != null && !commonPackageName.isEmpty()
? commonPackageName + ".$Proxy"
: "$Proxy";
Class<?> result;
synchronized (loader.proxyCache) {
result = loader.proxyCache.get(interfaceList);
if (result == null) {
//Proxy每生成一个$Proxy,nextClassNameIndex(静态)自动+1
String name = baseName + nextClassNameIndex++;
result = generateProxy(name, interfaces, loader, methodsArray, exceptionsArray);
loader.proxyCache.put(interfaceList, result);
}
}
return result
}
保存一份Map缓存,List<Class<?>>是key,value是interface服务的代理类Class<?> proxy。
遍历Class<?>数组,获取List<Method>,排序,增加equal,toString,hashCode三个基类方法。
根据name,Class<?>数组和List<Method>,native方法,即generateProxy方法,创建一个新类,命名为Xxx$Proxy数字,新类继承Proxy类,实现interface的方法。
generateProxy方法,创建Class<?>类型。
Map缓存防止每次对相同interface服务创建动态代理时都生成一次新类,反射影响性能。
getConstructor方法,获取新类带InvocationHandler参数的构造方法,创建新类实例对象。
protected Proxy(InvocationHandler h) {
this.h = h;
}
将新类的对象返回,对Proxy0类反编译,该类中所有的interface方法会触发super.h.invoke方法。父类的h是创建新类对象时传入的InvocationHandler对象。因此,每一个interface方法调用,被InvocationHandler的invoke方法拦截。
三、总结
动态代理这一套固定代码可以无侵入扩展各种服务interface的api。核心逻辑是创建一个实现interface接口方法的Proxy代理子类,实现的interface方法均由我们上层强行插入的InvocationHandler统一路由处理。
利用Proxy#方法,根据虚拟机运行时动态生成新类,创建一个对象,命名方式以$开头,Proxy+数字,继承Proxy。
新创建类和interface的关系加入Map缓存,防止每次创建同一个服务的动态代理类时都生成一次新类,影响性能。
任重而道远
网友评论