什么是代理
代理,即Proxy
。它的作用就是将原数据与后续的操作进行隔离,达到对修改封闭,对扩展开放的效果。
从现实生活中理解,厂商生产产品到代理商,而代理商负责找渠道销售产品。期间,厂商与销售人员不会有任何接触,也不管销售效果如何。
什么是静态代理
在Java中,通常会用代理模式来完成一些额外的操作。
例如,有一件商品,售价为25元,但是经过代理商之后,售价要提高5元。
代码语言:javascript复制// 定义货物的接口,以及获取价格的函数
public interface Cargo{
public int getPrice();
}
// 定义产品,实现Cargo接口,返回25元
public class Product implements Cargo{
@Override
public int getPrice(){
return 25;
}
}
// 定义产品的代理,实现Cargo接口,并且在原有的基础上增加5元再进行销售
public class ProductProxy implements Cargo{
private Product product;
public ProductProxy(Product product){
this.product = product;
}
@Override
public int getPrice(){
return product.getPrice() 5;
}
}
静态代理的优点
- 隐藏委托类的实现,保证委托类的独立
- 实现代理与委托类之间的解耦,不侵入委托类的代码
动态代理的背景
在使用静态代理的过程中,会产生如下问题:
- 大型项目的复杂度,如果代理过多的话,会导致维护成本很大,并且难以理解
- 通过接口实现的静态代理作用死板,对于功能的复用有很大影响
举例,我们希望统计产品在生产过程中(原材料采购 --> 材料加工 --> 产品制作 --> 后期包装等步骤)消耗的时间,然后产生报表。如果还使用静态代理的话,则这个代理类中都是相同的代码,并且后续再添加接口,仍然需要修改该代理类
于是,Java提出了动态代理的概念。
动态代理
动态代理,也就是在运行时创建的代理类。在运行过程中,会在虚拟机内部创建一个Proxy的类。通过实现InvocationHandler
的接口,来代理委托类的函数调用。
public class ProductProxy implements InvocationHandler{
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
还是以上述商品来举例。
代码语言:javascript复制 public class ProductProxy implements InvocationHandler{
// 被委托的对象
private Product product;
public ProductProxy(Product product){
this.product = product;
}
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("getPrice")){
// 如果调用的函数为getPrice的话,则 5
return method.invoke(product,args) 5;
}
return null;
}
}
public static void main(String []args){
// 创建代理类
ProductProxy proxy = new ProductProxy(new Product());
//获取代理类实例Product
Product product = (Product)(Proxy.newProxyInstance(Product.class.getClassLoader(), new Class[] {Product.class}, proxy));
// 调用getPrice的函数,就会走到动态代理的invoke函数中
product.getPrice();
}
通过动态代理,我们可以通过函数名来判断对应的函数以及对应操作,甚至于修改参数。
Retrofit中的动态代理
在Retrofit中,使用动态代理来对接口中的注释进行解析,解析后完成OkHttp的参数构建。
Retrofit的基本使用
首先来看一下使用Retrofit请求Github的的代码
- 通过
interface
以及注释定义了该为Get请求,并且路径为/
public interface GitHubService {
@GET("/")
Call<GitHubApiBean> listGitHubApis();
}
- 定义
baseUrl
为域名,并且添加GsonConverterFactory
作为Response的转换工厂,创建Retrofit对象
String url = "https://api.github.com/";
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)//url必须以‘/’结尾
.addConverterFactory(GsonConverterFactory.create())
.build();
- 调用函数,开始发起请求
//retrofit.create来生成一个接口实现类
GitHubService gitHubService=retrofit.create(GitHubService.class);
//调用指定方法
Call<GitHubApiBean> gitHubBeanCall=gitHubService.listGitHubApis();
//执行请求
gitHubBeanCall.enqueue(new Callback<GitHubApiBean>() {
@Override
public void onResponse(Call<GitHubApiBean> call, Response<GitHubApiBean> response) {
String authorizations_url= response.body().getAuthorizations_url();
String team_url= response.body().getTeam_url();
}
@Override
public void onFailure(Call<GitHubApiBean> call, Throwable t) {
Log.i("zfq", t.getMessage());
}
});
原理分析
在Retrofit的create
中会通过Proxy.newProxyInstance
来为传入的Service接口类创建一个代理对象,而当代理对象调用函数时,会调用动态代理的invoke
函数。
public <T> T create(final Class<T> 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 {
...
ServiceMethod<Object, Object> serviceMethod =
(ServiceMethod<Object, Object>) loadServiceMethod(method);
OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
而在invoke
函数中,会通过调用loadServiceMethod
函数,对Method中的注释进行解析,并且返回ServiceMethod
对象,传入OkHttpCall
中,构建OkHttp的请求。
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
...
// 通过注释中的Converter,创建Response中的转换器
responseConverter = createResponseConverter();
for (Annotation annotation : methodAnnotations) {
// 解析注释中的GET/Post、Multipart等等
parseMethodAnnotation(annotation);
}
...
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p ) {
Type parameterType = parameterTypes[p];
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
...
// 解析函数参数中的注释,例如Query,PartMap,FieldMap等
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
...
return new ServiceMethod<>(this);
}
Retrofit中的CallAdapter
CallAdapter
的作用则是将请求中的数据进行转换,通过adapt
函数进行转换,将A转换成B类型。
Retrofit.Builder test =new Retrofit.Builder().addCallAdapterFactory(new CallAdapter.Factory() {
@Override public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new CallAdapter<Object, Object>() {
@Override public Type responseType() {
return null;
}
@Override public Object adapt(Call<Object> call) {
return null;
}
};
}
});