代理模式
1 静态代理和动态代理
代理的概念:为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。
白话文:简单的说,就是类似于买东西,厂商负责生产,货物交给商店来代理出售。客人跟商店来交互,但是其实买的是厂商的东西。
静态代理
package com.proxy.inter;
/**
* 定义Demo接口
*/
public interface Demo {
public void save();
}
package com.proxy.impl;
import com.proxy.inter.Demo;
/**
* DemoImpl实现Demo接口并覆写save()方法
* 真实主题,执行具体业务
*/
public class DemoImpl implements Demo {
public void save() {
System.out.println("调用save()方法");
}
}
package com.proxy.impl;
import com.proxy.inter.Demo;
/**
* DemoImplProxy 也实现了Demo接口,并覆写了save()方法,增加了自己的业务
* 代理主题,负责其他业务的处理
*/
public class DemoImplProxy implements Demo {
Demo demoImpl = new DemoImpl();
public void save() {
System.out.println("开始记录日志");
demoImpl.save();
System.out.println("开始结束日志");
}
}
package com.proxy.impl;
import com.proxy.inter.Demo;
/**
* 开始记录日志
* 调用save()方法
* 开始结束日志
*/
public class Test {
public static void main(String[] args) {
Demo demoImplProxy = new DemoImplProxy();
demoImplProxy.save();
}
}
静态代理有一个缺点,每个代理类只能为一个接口服务,这样程序开发中必然会产生许多的代理类
所以我们就会想办法可以通过一个代理类完成全部的代理功能,那么我们就需要用动态代理
在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler 接口和 java.lang.reflect.Proxy 类的支持。
动态代理
java.lang.reflect.InvocationHandler接口的定义如下:
/**
*
*Object proxy:被代理的对象
*Method method:要调用的方法
*Object[] args:方法调用时所需要参数
*/
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
java.lang.reflect.Proxy类的定义如下:
/**
*CLassLoader loader:类的加载器
*Class<?> interfaces:得到全部的接口
*InvocationHandler h:得到InvocationHandler接口的子类的实例
*/
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException
具体实现
package com.proxy.inter;
/**
* 定义DemoFirst接口
*/
public interface DemoFirst {
public void saveFirst();
}
package com.proxy.impl;
import com.proxy.inter.DemoFirst;
/**
* DemoFirstImpl实现DemoFirst接口,覆写saveFirst()方法
* 真实主题,负责执行具体业务
*/
public class DemoFirstImpl implements DemoFirst {
@Override
public void saveFirst() {
System.out.println("调用saveFirst()方法");
}
}
package com.proxy.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* InvocationHandlerImple实现InvocationHandler接口,覆写invoke()方法
* 代理主题的业务写在invoke()方法中
*/
public class InvocationHandlerImpl implements InvocationHandler {
private Object target;
public InvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("target : " + target.getClass().getName());
System.out.println("proxy : " + proxy.getClass().getName());
System.out.println("method : " + method.getName());
System.out.println("args : " + args);
System.out.println("开始记录日志");
Object obj = method.invoke(target, args);
System.out.println("结束记录日志");
/*
* System.out.println("obj : " + obj.getClass().getName());
* 本例中saveXXX方法没有返回值所以obj会报空指针异常
*/
return obj;
}
}
package com.proxy.impl;
import java.lang.reflect.Proxy;
import com.proxy.inter.DemoFirst;
/*import com.proxy.inter.DemoSecond;*/
public class Test {
public static void main(String[] args) {
DemoFirst first = new DemoFirstImpl();
/*DemoSecond second = new DemoSecondImpl();*/
//取得代理对象
DemoFirst firstProxy = (DemoFirst) Proxy.newProxyInstance(first
.getClass().getClassLoader(), first.getClass().getInterfaces(),
new InvocationHandlerImpl(first));
//通过动态代理调用方法
firstProxy.saveFirst();
/*DemoSecond secondProxy = (DemoSecond) Proxy.newProxyInstance(second
.getClass().getClassLoader(), second.getClass().getInterfaces(),
new InvocationHandlerImpl(second));
secondProxy.saveSecond();*/
}
}
优缺点
缺点:
如果是代理类,那么调用getclass等方法的时候,会无法得到预期的结果。
代理模式的应用
代理模式是非常好用的,在很多的地方都有着用途。比如spring的AOP,
代理模式有多种应用场合,如下所述:
远程代理,也就是为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。比如说 WebService,当我们在应用程序的项目中加入一个 Web 引用,引用一个 WebService,此时会在项目中声称一个 WebReference 的文件夹和一些文件,这个就是起代理作用的,这样可以让那个客户端程序调用代理解决远程访问的问题;
虚拟代理,是根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。这样就可以达到性能的最优化,比如打开一个网页,这个网页里面包含了大量的文字和图片,但我们可以很快看到文字,但是图片却是一张一张地下载后才能看到,那些未打开的图片框,就是通过虚拟代里来替换了真实的图片,此时代理存储了真实图片的路径和尺寸;
安全代理,也可以是权限代理。用来控制真实对象访问时的权限。一般用于对象应该有不同的访问权限的时候;
延迟加载,用代理模式实现延迟加载的一个经典应用就在 Hibernate 框架里面。当 Hibernate 加载实体 bean 时,并不会一次性将数据库所有的数据都装载。默认情况下,它会采取延迟加载的机制,以提高系统的性能。Hibernate 中的延迟加载主要分为属性的延迟加载和关联表的延时加载两类。实现原理是使用代理拦截原有的 getter 方法,在真正使用对象数据时才去数据库或者其他第三方组件加载实际的数据,从而提升系统性能。
利用代理模式封装第三方网络请求
代理模式就是:为其他对象提供一种代理,以控制对这个对象的访问。
举个例子:没空下去吃饭,找个同事帮忙买饭就是代理模式;平常租房子,
嫌麻烦,说出房子条件,让找中介帮忙找,也是一种代理模式。
了解了代理模式,接下来的代码就好理解了。
首先我们的使用场景:项目刚开始,使用的是Volley请求框架,基本需求
都能满足。后来,出现了更完美的OkHttp请求框架,老板想让你使用最新的框架。
如果你在代码里请求网络的时候,都是直接使用的Volley代码直接进行操作的,那
就需要把每一处的请求都改一遍,非常麻烦。
代码
统一网络请求回调:
/**
* 接口统一回调
* */
public interface ICallBack {
//成功
void onSuccess(String result);
// 失败
void onFailed(String result);
}
代理接口:
/**
* 代理接口
* 封装各种三方类库的共同方法
* */
public interface IHttpProcessor {
// http 协议的四种动作 get post put delete
void get(String url ,Map<String ,Object> params,ICallBack callBack);
void post(String url,Map<String ,Object> params,ICallBack callBack);
}
代理对象:类似于一个工具类,可以直接调用相关方法
/**
* 代理类
*/
public class HttpUtils implements IHttpProcessor {
private static IHttpProcessor httpProcessor;
private static HttpUtils httpUtils;
public HttpUtils() {
}
// 单例
public static HttpUtils getInstance() {
if (httpUtils == null) {
synchronized (HttpUtils.class) {
if (httpUtils == null)
httpUtils = new HttpUtils();
}
}
return httpUtils;
}
public static void init(IHttpProcessor processor) {
httpProcessor = processor;
}
@Override
public void get(String url, Map<String, Object> params, ICallBack callBack) {
httpProcessor.get(url, params, callBack);
}
@Override
public void post(String url, Map<String, Object> params, ICallBack callBack) {
httpProcessor.post(url, params, callBack);
}
}
委托对象:即三方网络请求框架
首先,是Volley框架
public class VolleyProcessor implements IHttpProcessor {
private RequestQueue requestQueue;
public VolleyProcessor(Context context) {
requestQueue = Volley.newRequestQueue(context);
}
@Override
public void get(String url, Map<String, Object> params, final ICallBack callBack{
StringRequest request = new StringRequest(Request.Method.GET, url, new Listener<String>() {
@Override
public void onResponse(String response) {
callBack.onSuccess(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
callBack.onFailed(error.toString());
}
});
requestQueue.add(request);
}
@Override
public void post(String url, final Map<String, Object> params, final ICallBack callBack) {
StringRequest request = new StringRequest(url, new Listener<String>() {
@Override
public void onResponse(String response) {
callBack.onSuccess(response);
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
// TODO Auto-generated method stub
callBack.onFailed(error.toString());
}
}) {
@Override
protected Map<String, String> getParams() throws AuthFailureError {
//将Map<String, Object> 转为 <String, String>
Map<String, String> newMap = new HashMap<String, String>();
for (Map.Entry<String, Object> entry : params.entrySet()) {
newMap.put(entry.getKey(), (String) entry.getValue());
}
return newMap;
}
};
requestQueue.add(request);
}
}
然后是 Okhttp 框架:
public class OkHttpProcessor implements IHttpProcessor {
private OkHttpClient client;
private Handler mHandler;// okhttp 返回结果在子线程中,通过handler 发送到主线程
public OkHttpProcessor() {
client = new OkHttpClient();
mHandler = new Handler();
}
@Override
public void get(String url, Map<String,Object> params, final ICallBack callBack) {
// TODO Auto-generated method stub
Request request = new Request.Builder().get().url(url)
// 不添加,访问中文网络的时候回出错
.header("User-Agent", "a").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call arg0, final Response arg1) throws IOException {
if (arg1.isSuccessful()) {
final String result = arg1.body().string();
mHandler.post(new Runnable() {
@Override
public void run() {
callBack.onSuccess(result);
}
});
} else {
mHandler.post(new Runnable() {
@Override
public void run() {
callBack.onFailed(arg1.toString());
}
});
}
}
@Override
public void onFailure(Call arg0, final IOException arg1) {
mHandler.post(new Runnable() {
@Override
public void run() {
callBack.onFailed(arg1.toString());
}
});
}
});
}
@Override
public void post(String url, Map<String, Object> params, final ICallBack callBack) {
Request request = new Request.Builder().post(appendyBody(params))
.url(url).header("User-Agent", "a")
.addHeader("", "a").build();
client.newCall(request).enqueue(new Callback() {
@Override
public void onResponse(Call arg0, final Response arg1) throws IOException {
if (arg1.isSuccessful()) {
final String result = arg1.body().toString();
mHandler.post(new Runnable() {
@Override
public void run() {
callBack.onSuccess(result);
}
});
} else {
mHandler.post(new Runnable() {
@Override
public void run() {
callBack.onFailed(arg1.toString());
}
});
}
}
@Override
public void onFailure(Call arg0, final IOException arg1) {
mHandler.post(new Runnable() {
@Override
public void run() {
callBack.onFailed(arg1.toString());
}
});
}
});
}
/**
* 拼接参数
*/
public RequestBody appendyBody(Map<String, Object> params) {
FormBody.Builder builder = new FormBody.Builder();
if (params == null || params.isEmpty()) {
return builder.build();
}
for (Map.Entry<String, Object> map : params.entrySet()) {
builder.add(map.getKey(), map.getValue().toString());
}
return builder.build();
}
}
到这里代码已经写完。接下来就是见证奇迹的时刻,一行代码修改网络框架。
自定义 MyApplication
public class MyApplication extends Application{
@Override
public void onCreate() {
super.onCreate();
//绑定委托对象
//
HttpUtils.init(new OkHttpProcessor());
HttpUtils.init(new VolleyProcessor(this));
}
}
红色的标记,即可做到自如的切换网络请求框架。
如果想用OkHttp 即使用第一行,想用 Volley 使用第二行代码。
代码中使用: 例如 获取 天气信息
String url="http://www.weather.com.cn/data/cityinfo/101010100.html";
HttpUtils.getInstance().get(url, null, new ICallBack() {
@Override
public void onSuccess(String result) {
Log.d("log", "result=="+result);
}
@Override
public void onFailed(String result) {
Log.d("log",
"result=="+result);
}
});
注:Application类中是这个代码中唯一代码耦合的地方。