一.上面是代理模式?
所谓代理,就是一个人或者机构代表另一个人或者机构采取行动。
反应到程序上简单地理解就是A类有method1(),B类呢,持有A的引用,也有个method1()方法,B中的methd1的内容其实就是调用了A的method1,这样调用者调用B的method1其实本质是调用了A的method1,只是不是直接调用,B就像是A的一个代理一样,你找A做什么不要直接找它,找B来做。
代理模式常用的情况分为:静态代理和动态代理
二.静态代理
静态代理是指预先确定了代理与被代理者的关系,那映射到编程领域的话,就是指代理类与被代理类的依赖关系在编译期间就确定了。
用网上找的一个例子来讲吧
王二狗打官司(被代理的对象),请了一个律师替他上诉(代理对象)
首先定义一个代表诉讼的接口
public interface ILawSuit {
void submit(String proof);//提起诉讼
void defend();//法庭辩护
}
王二狗诉讼类型,实现ILawSuit接口
public class SecondDogWang implements ILawSuit {
public void submit(String proof) {
System.out.println(String.format("老板欠薪跑路,证据如下:%s", proof));
}
public void defend() {
System.out.println(String.format("铁证如山,%s还钱", "马旭"));
}
}
王二狗是不会上诉,于是请了个律师帮他搞
public class ProxyLawyer implements ILawSuit {
ILawSuit plaintiff;//持有要代理的那个对象
public ProxyLawyer(ILawSuit plaintiff) {
this.plaintiff=plaintiff;
}
public void submit(String proof) {
plaintiff.submit(proof);
}
public void defend() {
plaintiff.defend();
}
}
ok,律师请好了,组个队吧
如下代码,在编译期间王二狗就确定了要使用这个律师,而是不是上了法庭,一排律师中找一个。静态代理
public class ProxyFactory {
public static ILawSuit getProxy(){
return new ProxyLawyer(new SecondDogWang());
}
}
开打了
public class StaticMain {
public static void main(String[] args) {
ProxyFactory.getProxy().submit("工资流水在此");
ProxyFactory.getProxy().defend();
}
}
三.动态代理
动态代理本质上仍然是代理,情况与上面介绍的完全一样,只是代理与被代理人的关系是动态确定的,例如王二狗的同事牛翠花开庭前没有确定她的代理律师,而是在开庭当天当庭选择了一个律师,映射到编程领域为这个关系是在运行时确定的。
在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。
那么用代码看看牛翠花是怎么找律师的,如何在开庭当天找律师?
1.构建一个牛翠花诉讼类
public class CuiHuaNiu implements ILawSuit {
public void submit(String proof) {
System.out.println(String.format("老板欠薪跑路,证据如下:%s",proof));
}
public void defend() {
System.out.println(String.format("铁证如山,%s还牛翠花血汗钱","马旭"));
}
}
2.构建一个动态代理类
动态的律师出现了,只要是有诉讼需求的人(只要是实现ILawSuit 接口的类)我都可以接
public class DynProxyLawyer implements InvocationHandler {
private Object target;//被代理的对象
public DynProxyLawyer(Object obj) {
this.target = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("案件进展:" + method.getName());
Object result = method.invoke(target, args);
// 返回的是代理对象的执行函数的结果
return result;
}
}
public class DyncProxyFactory {
public static Object getDynProxy(Object target) {
InvocationHandler handler = new DynProxyLawyer(target);
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
}
}
3.开打
public class DyncMain {
public static void main(String[] args) {
ILawSuit proxy= (ILawSuit)DyncProxyFactory.getDynProxy(new CuiHuaNiu());
proxy.submit("工资流水在此");
proxy.defend();
}
}
解释一下:
首先Jdk的动态代理实现方法是依赖于接口的,首先使用接口来定义好操作的规范。然后通过Proxy类产生的代理对象调用被代理对象的操作,而这个操作又被分发给InvocationHandler接口的 invoke方法具体执行
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
}
此方法的参数含义如下
proxy:代表动态代理对象
method:代表正在执行的方法
args:代表当前执行方法传入的实参
返回值:表示当前执行方法的返回值
例如上面牛翠花案例中,我们使用Proxy类的newProxyInstance()方法生成的代理对象proxy去调用了proxy.submit("工资流水在此");操作,那么系统就会将此方法分发给invoke().其中proxy对象的类是系统帮我们动态生产的,其实现了我们的业务接口ILawSuit。
三.Retrofit中的代理模式使用
Retrofit 中使用了很多的设计模式,代理模式,工厂模式等等,我们一个一个来,先看看代理模式用在哪里
使用Retrofit 我们通常会在一个接口中定义网络接口,如下
public interface ServiceApi {
@GET("LoginServlet")// 登录接口 GET(相对路径)
Call<UserLoginResult> userLogin(@Query("userName") String userName,
@Query("password") String userPwd);
}
但是我们使用的时候,肯定不是直接ServiceApi调用他的userLogin,通常,我们会创建一个RetrofitClient
public class RetrofitClient {
private final static ServiceApi mServiceApi;
static {
OkHttpClient okHttpClient = new OkHttpClient
.Builder().addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
Log.e("TAG",message);
}
}).setLevel(HttpLoggingInterceptor.Level.BODY))
.build();
Retrofit retrofit = new Retrofit.Builder()
// 访问后台接口的主路径
.baseUrl("http://192.168.8.169:8080/OkHttpServer/")
// 添加 OkHttpClient,不添加默认就是 光杆 OkHttpClient
.client(okHttpClient)
.build();
// 创建一个 实例对象
mServiceApi = retrofit.create(ServiceApi.class);
}
public static ServiceApi getServiceApi() {
return mServiceApi;
}
}
注意看
.....
mServiceApi = retrofit.create(ServiceApi.class);
........
这句
那么源码中retrofit.create做了什么呢?我们源码简化下
public class Retrofit {
final String baseUrl;
final okhttp3.Call.Factory callFactory;
private Map<Method,ServiceMethod> serviceMethodMapCache = new ConcurrentHashMap<>();
public Retrofit(Builder builder) {
this.baseUrl = builder.baseUrl;
this.callFactory = builder.callFactory;
}
public <T> T create(Class<T> service) {
// 检验,是不是一个接口 ,不能让他继承子接口
// 重点
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class[]{service}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 每执行一个方法都会来这里
// 判断是不是 Object 的方法 ?
if(method.getDeclaringClass() == Object.class){
return method.invoke(this,args);
}
// 解析参数注解
ServiceMethod serviceMethod = loadServiceMethod(method);
// 2. 封装 OkHttpCall
OkHttpCall okHttpCall = new OkHttpCall(serviceMethod,args);
// 返回代理对象的执行结果,此处是OkHttpCall
return okHttpCall;
}
});
}
怎么样?怎么样?看到了什么,是不是使用了动态代理,当retrofit.create以后,创建了Api也就是示例中ServiceApi代理实例,调用ServiceAp的任何方法,都会走进
public Object invoke(Object proxy, Method method, Object[] args) throw
这个代理方法中,这个方法的三个参数我们文章开头讲过了,拿到Method,我们就可以通过反射的知识拿到注解的方法值,和注解的参数值
其实后面的 ServiceMethod serviceMethod = loadServiceMethod(method);就是把method传进去解析注解了
具体怎么做的呢?请看下文