注解 反射 可以查看上一章的讲解 如何应对Android面试官->Java中的注解、反射
代理模式
静态代理
代理模式类图
静态代理主要分三个角色:抽象角色、真实角色、代理角色
抽象角色:指代理角色和真实角色对外提供的公共方法,一般为一个接口;
csharp
public interface Message {
void message();
}
真实角色:需要实现抽象角色接口,定义了真实角色索要实现的业务逻辑,以便代理角色调用,也是真正的业务逻辑在此;
typescript
public class Alvin implements Message {
public void message() { // }
}
代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑来实现抽象方法,并可以附加自己的操作,将统一流程控制放到代理角色中处理;
通过代理,把调用者对真实对象的调用隔离了起来;
csharp
public class Agent implements Message() {
private Message message;
public Agent(Message message) {
this.message = message;
}
public void message() {
// before();
message.message();
after();
}
private void before() { }
private void after() { }
}
静态代理模式的实际应用
网络请求框架的封装
隔离层就是我们的代理对象,而真实对象就是我们的封装层,当我们发起网络请求的时候,业务并不需要关心具体使用的是哪个网络框架来发起请求,只需要操作隔离层的 HttpRequest 就行,当我们需要用 Volley 的时候,就只需要把我们的 Volley 的封装层实现赋值给隔离层的 HttpRequest 即可,那么就会使用 Volley 发起网络请求,如果要切换到 OkHttp,那么就只需要创建 OKHttp 的实现并赋值给隔离层的 HttpReqeust 即可;
动态代理
通过一个代理类,来实现全部的代理功能;在运行时再创建代理类和其实例,因此显然效率更低。要完成这个场景,需要在运行期动态创建一个Class。JDK提供了Proxy 来完成这件事;
基本使用
抽象角色
arduino
interface Api {
void test(String passName);
}
真实角色
typescript
class ApiImpl implements Api {
@Override public void test(String passName) {
System.out.println("真实实现:" + passName);
}
}
创建真实实例角色
ini
ApiImpl impl = new ApiImpl();
JDK动态代理实现
typescript
Proxy.newProxyInstance(getClass().getClassLoader(), new Class[] {Api.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) {
return Method.invoke(impl, args);
}
})
实际上, Proxy.newProxyInstance 会创建一个 Class,与静态代理不同,这个 Class 不是由具体的 .java 源文件编译而来,即没有真正的文件,只是在内存中按照 Class 格式生成了一个Class。
动态代理的原理
Android SDK 中的 Proxy.java 中的具体实现
ini
final Class<?> [] intfs = interfaces.clone(); // 对接口进行了一个拷贝,获取了一个 Class 对象的集合;
Class<?> cl = getProxyClass0(loader, intfs); // 获取一个 class
final Constructor<?> cons = cl.getConstuctor(constructorParams); // 获取这个 class 的构造函数
cons.newInstance(new Object[]{h}); // 对这个 class 进行实例化
所以:newProxyInstance() 返回的是一个 class 对象;
那么,这个 Class<?> cl 是怎么来的? 它里面的代码是什么样的呢?
那么这个 .class 的实例对象是怎么生成的?
这里要额外提到一点 类的生命周期
class 是由 javac 把 .java 文件编译成 .class,是一个实实在在存在的文件,存放在我们的硬盘中,而 动态代理 帮我们生成了一个 .class 是没有这个文件的,而是直接在内存中 一份实例化对象。
通过 ProxyGenerator.generateProxyClass 生成
ini
String var23 = var16 + "$Proxy" + var19;
byte[] var22 = ProxyGenerator.generateProxyClass(var23, var2, var17);
try {
return Proxy.defineClass0(var1, var23, var22, 0, var22.length);
} catch (ClassFormatError var14) {
throw new IllegalArgumentException(var14.toString());
}
也就是说,我们将 byte[] var22 这个数组写入到一个文件中,就可以看到 动态代理 帮我们生成的 class 实例对象 都有哪些内容
ini
String name = Api.class.getName()+"$Proxy0";
//生成代理指定接口的Class数据
byte[] bytes = ProxyGenerator.generateProxyClass(name, new Class[]{Api.class});
FileOutputStream fos = new FileOutputStream("lib/" + name+".class");
fos.write(bytes);fos.close();
生成的文件中可以查看我们的代理类
在初始化时,获得method 备用。而这个代理类中所有方法的实现变为:
这里的 h 其实就是 InvocationHandler 接口,所以我们在使用动态代理时,传递的InvocationHandler 就是一个监听,在代理对象上执行方法,都会由这个监听回调出来。
手写Retrofit实现
Retrofit 核心实现主要分为四部分注解、Retrofit、ServiceMethod、Parameter
Retrofit的核心实现主要是 动态代理、注解解析、构建请求参数、封装Call.Factory发起网络请求。
Retorfit时序图如下:
注解
手写只实现了 @POST、@GET、@QUERY、@FIELD
java
@Target(METHOD)
@Retention(RUNTIME)
public @interface POST {
String value() default "";
}
@Target(METHOD)
@Retention(RUNTIME)
public @interface GET {
String value() default "";
}
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Query {
String value();
}
@Target(PARAMETER)
@Retention(RUNTIME)
public @interface Field {
String value();
}
动态代理 MyRetrofit
OKHttp 发起网络请求,主要依靠的就是 Call.Factory HttpUrl
Call.Factory 提供了newCall方法用来发起请求,HttpUrl 用来构建请求参数和请求方式
MyRetrofit 也参考 Retorfit 采用 建造者模式实现,主要用来让调用方传递构建的 Call.Factory 和 HttpUrl,以及动态代理创建代理对象,调用 ServiceMethod 用来解析注解并封装请求参数;
kotlin
public class MyRetrofit {
// 参考 Retrofit 的实现,也增加一层缓存
final Map<Method, ServiceMethod> serviceMethodCache = new ConcurrentHashMap<>();
// 使用 OKhttp 提供的 Call.Factory
final Call.Factory callFactory;
// 使用 OKHttp 提供的 HttpUrl
final HttpUrl baseUrl;
MyRetrofit(Call.Factory callFactory, HttpUrl baseUrl) { this.callFactory = callFactory;
this.baseUrl = baseUrl;
}
// 参考 Retrofit 的动态代理
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, Object[] args) throws Throwable {
//解析这个method 上所有的注解信息
ServiceMethod serviceMethod = loadServiceMethod(method);
//args:
return serviceMethod.invoke(args);
}
});
}
private ServiceMethod loadServiceMethod(Method method) {
//先不上锁,避免synchronized的性能损失
ServiceMethod result = serviceMethodCache.get(method);
if (result != null)
return result;
//多线程下,避免重复解析,
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
/**
* 构建者模式,将一个复杂对象的构建和它的表示分离,可以使使用者不必知道内部组成的细节。
*/
public static final class Builder {
private HttpUrl baseUrl;
//Okhttp->OkhttClient
private okhttp3.Call.Factory callFactory;
//null
public Builder callFactory(okhttp3.Call.Factory factory) {
this.callFactory = factory;
return this;
}
public Builder baseUrl(String baseUrl) {
this.baseUrl = HttpUrl.get(baseUrl);
return this;
}
public MyRetrofit build() {
if (baseUrl == null) {
throw new IllegalStateException("Base URL required.");
}
okhttp3.Call.Factory callFactory = this.callFactory;
if (callFactory == null) {
callFactory = new OkHttpClient();
}
return new EnjoyRetrofit(callFactory, baseUrl);
}
}
}
ServiceMethod
用来解析注解,记录请求类型,参数、完整地址
ini
public class ServiceMethod {
private final Call.Factory callFactory;
private final String relativeUrl;
private final boolean hasBody;
private final ParameterHandler[] parameterHandler;
private FormBody.Builder formBuild;
HttpUrl baseUrl;
String httpMethod;
HttpUrl.Builder urlBuilder;
public ServiceMethod(Builder builder) {
baseUrl = builder.enjoyRetrofit.baseUrl;
callFactory = builder.enjoyRetrofit.callFactory;
httpMethod = builder.httpMethod;
relativeUrl = builder.relativeUrl;
hasBody = builder.hasBody;
parameterHandler = builder.parameterHandler;
//如果是有请求体,创建一个okhttp的请求体对象
if (hasBody) {
formBuild = new FormBody.Builder();
}
}
public Object invoke(Object[] args) {
/**
* 1 处理请求的地址与参数
*/
for (int i = 0; i < parameterHandler.length; i++) {
ParameterHandler handlers = parameterHandler[i];
// handler内本来就记录了key,现在给到对应的value
handlers.apply(this, args[i].toString());
}
//获取最终请求地址
HttpUrl url;
if (urlBuilder == null) {
urlBuilder = baseUrl.newBuilder(relativeUrl);
}
url = urlBuilder.build();
//请求体
FormBody formBody = null;
if (formBuild != null) {
formBody = formBuild.build();
}
Request request = new Request.Builder().url(url).method(httpMethod, formBody).build();
return callFactory.newCall(request);
}
// get请求,把 k-v 拼到 url 里面
public void addQueryParameter(String key, String value) {
if (urlBuilder == null) {
urlBuilder = baseUrl.newBuilder(relativeUrl);
}
urlBuilder.addQueryParameter(key, value);
}
// Post,把 k-v 放到 请求体中
public void addFiledParameter(String key, String value) {
formBuild.add(key, value);
}
public static class Builder {
private final MyRetrofit enjoyRetrofit;
private final Annotation[] methodAnnotations;
private final Annotation[][] parameterAnnotations;
ParameterHandler[] parameterHandler;
private String httpMethod;
private String relativeUrl;
private boolean hasBody;
public Builder(MyRetrofit enjoyRetrofit, Method method) {
this.enjoyRetrofit = enjoyRetrofit;
//获取方法上的所有的注解
methodAnnotations = method.getAnnotations();
//获得方法参数的所有的注解 (一个参数可以有多个注解,一个方法又会有多个参数)
parameterAnnotations = method.getParameterAnnotations();
}
public ServiceMethod build() {
/**
* 1 解析方法上的注解, 只处理POST与GET
*/
for (Annotation methodAnnotation : methodAnnotations) {
if (methodAnnotation instanceof POST) {
//记录当前请求方式
this.httpMethod = "POST";
//记录请求url的path
this.relativeUrl = ((POST) methodAnnotation).value();
// 是否有请求体
this.hasBody = true;
} else if (methodAnnotation instanceof GET) {
this.httpMethod = "GET";
this.relativeUrl = ((GET) methodAnnotation).value();
this.hasBody = false;
}
// 待处理其他注解
}
/**
* 2 解析方法参数的注解
*/
int length = parameterAnnotations.length;
parameterHandler = new ParameterHandler[length];
for (int i = 0; i < length; i++) {
// 一个参数上的所有的注解
Annotation[] annotations = parameterAnnotations[i];
// 处理参数上的每一个注解
for (Annotation annotation : annotations) {
//todo 可以加一个判断:如果httpMethod是get请求,现在又解析到 Filed 注解,可以提示使用者使用 Query 注解
if (annotation instanceof Field) {
//得到注解上的value: 请求参数的key
String value = ((Field) annotation).value();
parameterHandler[i] = new ParameterHandler.FiledParameterHandler(value);
} else if (annotation instanceof Query) {
String value = ((Query) annotation).value();
parameterHandler[i] = new ParameterHandler.QueryParameterHandler(value);
}
}
}
return new ServiceMethod(this);
}
}
}
ParameterHandler
QUERY、FIELD 请求参数封装,桥接到 HttpUrl 的addQueryParameter formBuild.add
scala
public abstract class ParameterHandler {
abstract void apply(ServiceMethod serviceMethod, String value);
static class QueryParameterHandler extends ParameterHandler {
String key;
public QueryParameterHandler(String key) {
this.key = key;
}
//serviceMethod: 回调
@Override
void apply(ServiceMethod serviceMethod, String value) {
serviceMethod.addQueryParameter(key,value);
}
}
static class FiledParameterHandler extends ParameterHandler {
String key;
public FiledParameterHandler(String key) {
this.key = key;
}
@Override
void apply(ServiceMethod serviceMethod, String value) {
serviceMethod.addFiledParameter(key,value);
}
}
}
简历润色
简历中可写上:深度理解 Retofit 实现原理,理解 注解、反射、动态代理,可手写 Retofit 核心实现