一.核心思想
为其他对象提供代理以控制对这个对象的访问,代理对象起到了中介作用,不影响其他对象原有的功能,可以在其基础上新增额外的服务。
解释: A要访问a, A--->B(代理)--->a, 这个过程B代理可以做一些扩展性的东西, 而且不会影响a原有的功能.
二. 分类
1. 静态代理:
2. 动态代理
三. 简单实现
例如: 计算吃饭时间
如果不使用代理的情况
public interface IDinner {
String TAG = "66";
void eat();
}
public class LiysBusiness implements IDinner {
@Override
public void eat() {
Log.d(TAG, "开始时间: " +new Date().getTime());
Log.d(TAG, "liys吃饭");
Log.d(TAG, "结束时间: " +new Date().getTime());
}
}
这种方式有个致命的缺点:
如果想分别计算几百人吃饭的时间, 那重复的代码就多了去.
下面我们看看怎么用代理模式解决这个问题的.
1.静态代理
public class LiysBusiness implements IDinner {
@Override
public void eat() {
Log.d(TAG, "liys吃饭");
}
}
public class HongDinner implements IDinner {
@Override
public void eat() {
Log.d(TAG, "hong吃饭");
}
}
代理类
public class ProxyDinner implements IDinner {
IDinner mIDinner;
public ProxyDinner(@NonNull IDinner iDinner){
this.mIDinner = iDinner;
}
@Override
public void eat() {
if(mIDinner != null){
Log.d(TAG, "开始时间: " +new Date().getTime());
mIDinner.eat();
Log.d(TAG, "结束时间: " +new Date().getTime());
}
}
}
//使用
//liys
ProxyBusiness proxyDinner = new ProxyBusiness(new LiysBusiness());
proxyDinner.handle();
//hong
proxyDinner = new ProxyBusiness(new HongBusiness());
proxyDinner.handle();
打印结果:
log1.png
这样就解决了上面的问题了.
使用静态代理的好处:
①. 降低耦合性, 每个实现类只需要做属于自己的事情, 其它不需要管, 符合单一职责原则.
②. 扩展性强, 实现类的逻辑不用做任何改变, 即可实现, 符合开闭原则
思考: 这样是不是就完美了呢? 如果我想计算洗澡的时间, 是不是还得写多一个洗澡的代理类ProxyBathe, 如果我还想计算睡觉的时间呢? 等等.这个时候代理类就会越来越多. 怎么办呢? 能不能用一个代理类解决这些问题? 这个时候就得看动态代理了.
2. 动态代理
Java里面其实为我们提供了一套动态代理机制, 我们先看关键类InvocationHandler(其实是一个接口).
package java.lang.reflect;
public interface InvocationHandler {
/**
* @param proxy 被代理的对象
* @param method 被代理的方法
* @param args 被代理方法参数
* @return 返回代理对象
* @throws Throwable
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
下面看具体实现
/**
* 代理类(计算时间)
*/
public class TimeInvocationHandler implements InvocationHandler{
String TAG = "66";
//被代理的对象
private Object mObject;
public TimeInvocationHandler(Object object){
this.mObject = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Log.d(TAG, "开始时间: " +new Date().getTime());
Object voidObject = method.invoke(mObject,args);
Log.d(TAG, "结束时间: " +new Date().getTime());
return voidObject;
}
}
//新增洗澡功能
public interface IBathe {
String TAG = "66";
void bathe();
}
public class Bathe implements IBathe{
public void bathe(){
try {
Log.d(TAG, "洗澡..");
Thread.sleep(123);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//使用
// 返回的是 IBank 的一个实例对象,这个对象是由 Java 给我们创建的 ,调用的是 jni
//计算吃饭时间
IDinner iDinner = (IDinner) Proxy.newProxyInstance(
IDinner.class.getClassLoader(), // ClassLoader
new Class<?>[]{IDinner.class}, // 目标接口
new TimeInvocationHandler(new LiysDinner()) //TimeInvocationHandler (这个类是关键)
);
iDinner.eat();
//计算洗澡时间
IBathe iBathe = (IBathe) Proxy.newProxyInstance(
IBathe.class.getClassLoader(),
new Class<?>[]{IBathe.class},
new TimeInvocationHandler(new Bathe())
);
iBathe.bathe();
打印结果:
log2.png
这样就解决问题了, 以上就是动态代理的简单实现.
如果想深入了解Proxy工作原理, 请参考: Proxy.newProxyInstance的秘密
四. 实战篇
源码这里只是大概介绍, 重点还是在动态代理
Retrofit的创建
首先我们看Retrofit最简单的运用, 用过的应该都能看懂.
public interface ServiceApi {
@POST("api/liys/login")// 登录接口 GET(相对路径)
Call<User> userLogin(
// @Query(后台需要解析的字段)
@Query("userName") String userName,
@Query("password") String userPwd);
}
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://192.168.1.201")
.addConverterFactory(ScalarsConverterFactory.create()) //返回值解析成String
.build();
// 创建一个 实例对象
ServiceApi mServiceApi = retrofit.create(ServiceApi.class);
mServiceApi.userLogin("123", "456")
.enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {}
@Override
public void onFailure(Call<String> call, Throwable t) {}
});
一开始看到这种用法的时候, 我一脸懵逼, 非常不习惯, 后面才慢慢习惯. 我们这里重点关注这行代码:
ServiceApi mServiceApi = retrofit.create(ServiceApi.class);
看看retrofit.create源码(版本:2.3.0): 省略部分代码
public <T> T create(final Class<T> service) {
//检测传进来的service是否是接口, 如果不是则抛出异常throw new IllegalArgumentException("API declarations must be interfaces.");
Utils.validateServiceInterface(service);
//动态代理(重点)
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
new InvocationHandler() {
@Override public Object invoke(Object proxy, Method method, @Nullable Object[] args)
throws Throwable {
//执行接口上的方法时都要先进到这个方法里, 例如:mServiceApi.userLogin("123", "456")
// 解析接口上的注解 和 方法参数, 经过一系列的操作,封装成Call或别的对象返回去
return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
}
});
}
网友评论