1.静态代理
比如说本人要买华为手机,可以自己买,也可以让别人帮着买
public interface Buyer {
void buy();
}
public class Me implements Buyer {
@Override
public void buy() {
System.out.println("I want to buy HUAWEI");
}
}
现在本人比较忙,所以决定让姐姐帮我代购(当然,也可以是其他人)
public class BuyProxy implements Buyer {
private Buyer mBuyer;
public BuyProxy(Buyer buyer) {
mBuyer = buyer;
}
@Override
public void buy() {
System.out.println("I am BuyProxy");
mBuyer.buy();
}
}
以上,就是常见的静态代理模式
由此可见,静态代理其实就是代理一类行为
那如果下次不是代购,而是代课了呢?(这里只是举个例子)
2.动态代理
我们为代课进行了如下的实现
public interface TakeLesson {
void take();
}
public class Me implements Buyer, TakeLesson {
@Override
public void buy() {
System.out.println("I want to buy HUAWEI");
}
//新增这个接口的实现
@Override
public void take() {
System.out.println("I want someone to have Math class. I will give 50 yuan");
}
}
public class TakeLessonProxy implements TakeLesson {
private TakeLesson mTaker;
public TakeLessonProxy(TakeLesson taker) {
mTaker = taker;
}
@Override
public void take() {
System.out.println("This is TakeLessonProxy");
mTaker.take();
}
}
测试代码
TakeLesson taker = new TakeLessonProxy(new Me());
taker.take();
打印出 This is TakeLessonProxy.I want someone to have Math class. I will give 50 yuan
第二个代理操作算是实现了
问题是以后如果还有别的代理操作呢?有没有方法把所有的都统一起来.
其实是有的,就是动态代理,它的核心类就是 InvocationHandler
public class ProxyHandler implements InvocationHandler {
private Object object;
public ProxyHandler(Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//proxy其实就是ProxyHandler的实例
//method就是接口方法
//args就是接口的参数
method.invoke(object, args);//调用真正的操作函数,其实还可以在之前或者之后添加别的操作
return null;
}
}
测试代码
Me me = new Me();
ProxyHandler handler = new ProxyHandler(me);
Buyer operator = (Buyer) Proxy.newProxyInstance(
Buyer.class.getClassLoader(), // 传入ClassLoader
new Class[] { Buyer.class }, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
operator.buy();
TakeLesson operator2 = (TakeLesson) Proxy.newProxyInstance(
TakeLesson.class.getClassLoader(), // 传入ClassLoader
new Class[] { TakeLesson.class }, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
operator2.take();
输出 I want to buy HUAWEI.I want someone to have Math class. I will give 50 yuan.
由此可见,动态代理可以代理多种行为(省掉了两个代理的实现类)具体的实现原理网上可以搜一下,不难找
那具体的动态代理操作又是如何实现的呢?
再以这段代码为例
Me me = new Me();
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); //设置系统属性
ProxyHandler handler = new ProxyHandler(me);
Buyer operator = (Buyer) Proxy.newProxyInstance(
Buyer.class.getClassLoader(), // 传入ClassLoader
new Class[] { Buyer.class }, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
operator.buy();
添加完System.getProperties(),就可以在项目名称\com\sun\proxy目录下找到对应的生成的代理类,然后用Luyten进行反编译得到
package com.sun.proxy;
import buy.*;
import java.lang.reflect.*;
public final class $Proxy0 extends Proxy implements Buyer
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(final InvocationHandler invocationHandler) {
super(invocationHandler);
}
public final boolean equals(final Object o) {
try {
return (boolean)super.h.invoke(this, $Proxy0.m1, new Object[] { o });
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final String toString() {
try {
return (String)super.h.invoke(this, $Proxy0.m2, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final void buy() {
try {
super.h.invoke(this, $Proxy0.m3, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
public final int hashCode() {
try {
return (int)super.h.invoke(this, $Proxy0.m0, null);
}
catch (Error | RuntimeException error) {
throw;
}
catch (Throwable t) {
throw new UndeclaredThrowableException(t);
}
}
static {
try {
$Proxy0.m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
$Proxy0.m2 = Class.forName("java.lang.Object").getMethod("toString", (Class<?>[])new Class[0]);
$Proxy0.m3 = Class.forName("buy.Buyer").getMethod("buy", (Class<?>[])new Class[0]);
$Proxy0.m0 = Class.forName("java.lang.Object").getMethod("hashCode", (Class<?>[])new Class[0]);
}
catch (NoSuchMethodException ex) {
throw new NoSuchMethodError(ex.getMessage());
}
catch (ClassNotFoundException ex2) {
throw new NoClassDefFoundError(ex2.getMessage());
}
}
}
我们就看buy函数,其实他就是调的InvocationHandler里面的invoke函数
于是,我们可以总结如下:
Proxy.newProxyInstance会生成一个代理类来继承接口,然后具体的实现还是由InvocationHandler的invoke函数决定的.如果没有method.invoke这一句,operator.buy()不会有任何输出
说白了,buy和takeLesson必须是相类似的操作(可以是不同接口).如果buy和takeLesson的操作差别很大,那么必须在invoke函数里面if else,那么这样的动态代理就没有意义
而网络请求的操作基本一样,都是构造url,顶多就是参数的区别.那么retrofit的动态代理基本也就明朗了
- 1.new OkhttpClient(看代码就知道在build函数里面)
- 2.继承InvocationHandler.当调用接口函数的时候就会走到invoke函数,接下来就很明显了,就是通过各种参数组成call,然后交给executor来执行(InvocationHandler的invoke函数肯定不会调用method.invoke,因为没有为接口实现具体的实现类)
3.retrofit
重点看一下create方法
public <T> T create(final Class<T> service) {
validateServiceInterface(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);
}
});
}
很明显出现了预料中的newProxyInstance动态代理。再仔细看看里面出现了啥
重点在 loadServiceMethod(method).invoke(args != null ? args : emptyArgs); 这一句
loadServiceMethod很明显就是加载了所有interface,然后是invoke方法
HttpServiceMethod的invoke
@Override
final @Nullable
ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
看到了熟悉的OkHttpCall了吧。(Retrofit的build函数里面会new OkHttpClient的,其实build函数里面还生成了很多默认的一些配置,可以看看,比较简单)
由此可见,retrofit的动态代理代理的是OkHttpCall
网友评论