定义
给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
目的
- 通过引入代理对象的方式来简介访问目标对象,防止直接访问目标对象给系统带来的不必要的复杂性
- 通过代理对象对原有的业务进行增强
静态代理及问题
public class Client {
public static void main(String[] args) {
//ManToolsFactoryInterface是接口,AToolsFactory是实体工厂,SalesmanAndy是代理
ManToolsFactoryInterface aFactory = new AToolsFactory();
SalesmanAndy andy = new SalesmanAndy(aFactory);
andy.saleManTools("D");
//WomanToolsFactoryInterface是接口,BToolsFactory是实体工厂,SalesmanBob是代理
WomanToolsFactoryInterface bFactory = new BToolsFactory();
SalesmanBob bob = new SalesmanBob(bFactory);
bob.saleWomanTools(1.8f);
}
}
public class AToolsFactory implements ManToolsFactoryInterface {
@Override
public void saleManTools(String size) {
System.out.println("按需求定制了一个size为"+size+"的女model");
}
}
public class SalesmanAndy implements ManToolsFactoryInterface {
/*包含真实的对象*/
public ManToolsFactoryInterface factory;
public Mark(ManToolsFactoryInterface factory) {
this.factory = factory;
}
/*前置处理器*/
private void doSthAfter() {
System.out.println("精美包装,快递一条龙服务");
}
/*后置处理器*/
private void doSthBefore() {
System.out.println("根据需求,进行市场调研和产品分析");
}
@Override
public void saleManTools(String size) {
doSthAfter();
factory.saleManTools(size);
doSthBefore();
}
}
- 每来一个需求,就得生成一个代理类对象(SalesmanAndy、SalesmanBob)
- 代理类对象持有目标对象(factory),当接口发生变化,修改维护变得复杂
违反开闭原则,导致
- 拓展性差
- 可维护性差
动态代理及问题
public class MarkCompany implements InvocationHandler {
/*持有的真实对象*/
private Object factory;
public Object getFactory() {
return factory;
}
public void setFactory(Object factory) {
this.factory = factory;
}
/*通过Proxy获得动态代理对象*/
public Object getProxyInstance(){
return Proxy.newProxyInstance(factory.getClass().getClassLoader(),
factory.getClass().getInterfaces(), this);
}
/*通过动态代理对象方法进行增强*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
doSthAfter();
Object result = method.invoke(factory, args);
doSthBefore();
return result;
}
/*前置处理器*/
private void doSthAfter() {
System.out.println("精美包装,快递一条龙服务");
}
/*后置处理器*/
private void doSthBefore() {
System.out.println("根据需求,进行市场调研和产品分析");
}
}
public class Client {
public static void main(String[] args) {
ManToolsFactory aFactory = new AToolsFactory();
MarkCompany markCompany = new MarkCompany();
markCompany.setFactory(aFactory);
//张三来了
ManToolsFactoryInterface employee1 = (ManToolsFactoryInterface)markCompany.getProxyInstance();
employee1.saleManTools("E");
//张三老婆来了
WomanToolsFactoryInterface bToolsFactory = new BToolsFactory();
markCompany.setFactory(bToolsFactory);
WomanToolsFactoryInterface employee2
= (WomanToolsFactoryInterface)markCompany.getProxyInstance();
employee2.saleWomanTools(1.9f);
//动态代理,不出现代理类、代理对象,运行时出现
}
}
-
需要使用到反射,效率比静态代理低
-
受限:因为java单继承,所以只能针对接口创建代理类,不能针对类创建代理类
-
cglib 后端Spring使用比较多
-
重点类:Proxy(类比有资源的代购人) InvocationHandler(优质的代购服务,包括售前 购买 售后)
对于动态代理类来说,没有编写Java源文件这一步骤
注:代理模式中 代理类-代理对象和实体类-真实对象都需要实现需要被代理的接口
Retrofit中的动态代理
了解Retrofit用动态代理解决了什么问题。
下面代码是OkHttp一个GET请求实例
//第一步:初始化
OkHttpClient client = new OkHttpClient();
//第二步获取请求对象
Request request = new Request.Builder()
.url(url)
.build();
//执行请求获取服务器响应对象
Response response = client.newCall(request).execute();
response.body().string();
再看Retrofit如何发起请求的
//第一步,初始化,配置需要的物料,例如请求地址的根路径,转化工厂,拦截器什么的
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
// Create an instance of our GitHub API interface.
//第二步使用动态代理创建代理类对象
GitHub github = retrofit.create(GitHub.class);
// Create a call instance for looking up Retrofit contributors.
// 然后调用代理类的方法获取请求对象
Call<List<Contributor>> call = github.contributors("square", "retrofit");
// Fetch and print a list of the contributors to the library.
//第三步 执行请求获取服务器响应对象
List<Contributor> contributors = call.execute().body();
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
都是3步走
- 初始化
- 创建请求对象
- 发送请求获取数据.
Retrofit用这两行替代了OkHttp的这两行
GitHub github = retrofit.create(GitHub.class);
Call<List<Contributor>> call = github.contributors("square", "retrofit");
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(@Path("owner") String owner,@Path("repo") String repo);
}
String url ="baseUrl"+/repos/"+"square"+"/"+"retrofit"+"/contributors"
Request request = new Request.Builder()
.url(url)
.build();
Response response = client.newCall(request).execute();
String result=response.body().string()
return GsonUtlis.from(result);
其实优势已经出来了,okhttp url的拼接,是由我们来做,body的数据是字符串或者其它,还要手动处理成gson或者其它,这还只是get请求。创建请求对象的时候还要创建请求体,但是Retrofit就更简单,按照暴露的接口,传参就好了,帮你返回你想要对象,你什么都不用做,只用处理传入参数,获取结果。实现了一个黑盒。
了解Retrofit是如何做到的
如何动态产生请求对象Request,弄明白这两行我们就算大功告成了.
GitHub github = retrofit.create(GitHub.class);
Call<List<Contributor>> call = github.contributors("square", "retrofit");
- 首先定义了一个接口,让用户告诉我,你是什么请求,传了那些参数,想获得什么对象.
public interface GitHub {
@GET("/repos/{owner}/{repo}/contributors")
Call<List<Contributor>> contributors(
@Path("owner") String owner,
@Path("repo") String repo);
}
- 拿到这个接口,处理这个数据,如何通过接口获取数据呢?
下面看Retrofit源码
public <T> T create(final Class<T> service) {
// 删除一些校验接口合法性的代码
//第一个参数类加载器,第二个要代理的接口对象,第三个代理对象执行方法时的回调
return (T) Proxy.newProxyInstance(
service.getClassLoader(),
new Class<?>[] { service },
new InvocationHandler() {
//获取用户哪个平台,有android和java8
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(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);
}
});
}
这里最核心的就是loadServiceMethod(method)获取被代理对象,这里你可要注意,这里loadServiceMethod返回的是ServiceMethod。
ServiceMethod<?> loadServiceMethod(Method method) {
//从缓存中获取,因为重新获取一遍还是挺麻烦的
ServiceMethod<?> result = serviceMethodCache.get(method);
if (result != null) return result;
synchronized (serviceMethodCache) {
result = serviceMethodCache.get(method);//这里又获取了一次
if (result == null) {
//生成ServiceMethod的地方
result = ServiceMethod.parseAnnotations(this, method);
serviceMethodCache.put(method, result);
}
}
return result;
}
上面主要看的是 ServiceMethod.parseAnnotations(this, method);
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, method);
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(method,
"Method return type must not include a type variable or wildcard: %s", returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
}
abstract @Nullable T invoke(Object[] args);
}
上面主要看的是HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
继续追踪到HttpServiceMethod
static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
boolean isKotlinSuspendFunction = requestFactory.isKotlinSuspendFunction;
boolean continuationWantsResponse = false;
boolean continuationBodyNullable = false;
Annotation[] annotations = method.getAnnotations();
Type adapterType;
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType = Utils.getParameterLowerBound(0,
(ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response<T>.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
adapterType = method.getGenericReturnType();
}
CallAdapter<ResponseT, ReturnT> callAdapter =
createCallAdapter(retrofit, method, adapterType, annotations);
Type responseType = callAdapter.responseType();
if (responseType == okhttp3.Response.class) {
throw methodError(method, "'"
+ getRawType(responseType).getName()
+ "' is not a valid response body type. Did you mean ResponseBody?");
}
if (responseType == Response.class) {
throw methodError(method, "Response must include generic type (e.g., Response<String>)");
}
// TODO support Unit for Kotlin?
if (requestFactory.httpMethod.equals("HEAD") && !Void.class.equals(responseType)) {
throw methodError(method, "HEAD method must use Void as response type.");
}
Converter<ResponseBody, ResponseT> responseConverter =
createResponseConverter(retrofit, method, responseType);
okhttp3.Call.Factory callFactory = retrofit.callFactory;
if (!isKotlinSuspendFunction) {
return new CallAdapted<>(requestFactory, callFactory, responseConverter, callAdapter);
} else if (continuationWantsResponse) {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForResponse<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter);
} else {
//noinspection unchecked Kotlin compiler guarantees ReturnT to be Object.
return (HttpServiceMethod<ResponseT, ReturnT>) new SuspendForBody<>(requestFactory,
callFactory, responseConverter, (CallAdapter<ResponseT, Call<ResponseT>>) callAdapter,
continuationBodyNullable);
}
}
create方法里的return语句中,就返回了上面的HttpServiceMethod,并调用了下面的invoke方法
@Override final @Nullable ReturnT invoke(Object[] args) {
Call<ResponseT> call = new OkHttpCall<>(requestFactory, args, callFactory, responseConverter);
return adapt(call, args);
}
这里就获得了咱们的 Call<List<Contributor>> call,至于adapter()方法的后续追踪,这里没有详细展开去分析,因为这里和我们动态代理没有关系了。











网友评论