最近在整理Retrofit源码的时候想起原先学过的一种设计模式 代理模式,而Retrofit的create方法就是通过Java运行时的动态代理实现的。这里再结合Retrofit#create方法的源码总结一下代理模式。
https://blog.csdn.net/u013728021/article/details/70740152
代理模式 的好处
1.可以隐藏委托类的实现;
2.可以实现客户与委托类间的解耦,在不修改委托类代码的情况下能够做一些额外的处理。动态代理
代理类在程序运行时创建的代理方式被成为 动态代理
注意这里的运行时
首先看一下在 Retrofit#create 方法中使用到的动态代理
public <T> T create(final Class<T> service) {
//对service做验证
Utils.validateServiceInterface(service);
//是否要激进的验证,默认是关闭的
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
private final Platform platform = Platform.get();
private final Object[] emptyArgs = new Object[0];
@Override public @Nullable Object invoke(Object proxy, Method method,
@Nullable Object[] args) throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
可以看到核心代码是Proxy.newProxyInstance的方法,接下来咱们先看一下Proxy.newProxyInstance方法和该方法的三个参数与返值
/**
* 三个参数
* loader
* 提供一个ClassLoader生成一个class,提供一个载体,随便一个classloader都可以,就像是
* 装东西的箱子,这里不是关键。
*
* interfaces
* 代理对象所需要实现的所有接口 数组中的每一个对象都要被实现
*
* h
* InvocationHandler 这个又是Proxy.newProxyInstance的核心,咱们下面分析
*
* 返回值
* return 根据代理接口创建的真正代理对象
*/
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
// 检查 h 不为空,否则抛异常
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
//核心方法,查阅或者生成指定的代理class,
//Look up or generate the designated proxy class.
Class<?> cl = getProxyClass0(loader, intfs);
//根据生成的class通过反射获取构造函数对象并生成代理类实例
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
cons.setAccessible(true);
}
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);
}
}
private static Class<?> getProxyClass0(ClassLoader loader,
Class<?>... interfaces) {
if (interfaces.length > 65535) {
throw new IllegalArgumentException("interface limit exceeded");
}
//如果该接口的代理class已经被提供的loader实现,直接从缓存中复制。
//否则通过ProxyClassFactory创建该代理class。
// If the proxy class defined by the given loader implementing
// the given interfaces exists, this will simply return the cached copy;
// otherwise, it will create the proxy class via the ProxyClassFactory
return proxyClassCache.get(loader, interfaces);
}
在getProxyClass0的注释中可以看到ProxyClassFactory,该类是Proxy里的一个内部类,用来生成代理类,apply()方法 最后调用 ProxyGenerator.generateProxyClass() 方法来完成生成字节码的操作,这里不讲它是如何生成的,在回到我们的 InvocationHandler 接口
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
InvocationHandler接口中只有一个invoke回调方法,没错,最后就是通过这个 invoke 在运行时通过反射的方式进行处理,拿Retrofit官方的例子来说,动态代理在运行时会生成一个如下的类的伪代码。
public class TestServiceProxy implements TestService{
InvocationHandler invocationHandler=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
};
@Override
public Call<List<Repo>> listRepos(String user) {
Method method = new TestService.class.getDeclareMethod("listRepos",String.class);
return invocationHandler.invoke(this,method,user);
}
}
本篇是对Retrofit源码的一个补充,就先写这么多吧。