1.为什么要使用代理模式
在爱情公寓中,有这样一个场景:曾小贤的电话编辑会帮他拦截一部分没有“无聊”的来电,如果没有这个电话编辑会怎样呢?曾小贤就要每天处理大量无意义的来电,而且有价值的来电没办法快速处理掉。甚至如果有一天要增加奖励每天价值比较高的来电,那曾小贤根本就忙不过来了。这个场景和代理模式的原理一样的,就是在源对象与目标对象之间起到一个中介或者保护目标对象的作用。
2.实例
模拟一个请求实例,通过代理对象对请求处理前做基本的校验和请求处理后的数据进行加密或者标识等操作。
2.1 请求处理类接口
public interface RequestProcessor {
void process();
}
2.2 默认的请求处理器(含核心处理逻辑)
public class DefaultRequestProcessor implements RequestProcessor{
@Override
public void process() {
System.out.println("这是一个默认请求处理器,正在处理一个一个请求");
}
}
2.3 请求处理器的代理类
public class RequestProcessorProxy implements RequestProcessor {
private RequestProcessor requestProcessor;
public RequestProcessorProxy(RequestProcessor requestProcessor) {
this.requestProcessor = requestProcessor;
}
@Override
public void process() {
preProcess();
requestProcessor.process();
postProcess();
}
public void preProcess(){
System.out.println("请求前检查参数,白名单等");
}
public void postProcess(){
System.out.println("请求结束对请求结果压缩,加密,添加标识等操作");
}
}
实现RequestProcessor接口可以让用户使用代理类无感知,扩展更方便
2.4 测试
public class TestProxy {
public static void main(String[] args) {
RequestProcessor requestProcessorProxy = new RequestProcessorProxy(new DefaultRequestProcessor());
requestProcessorProxy.process();
}
}
-------------------------console结果
请求前检查参数,白名单等
这是一个默认请求处理器,正在处理一个一个请求
请求结束对请求结果压缩,加密,添加标识等操作
上面的实例其实属于静态代理
,它存在一个明显的缺点:假如我要对很多个类的某些方法进行代理,增加打印入参的功能。那么我们需要增加很多个代理类,而每个代理类的添加的功能都很简单只是打印一下入参,这明显是得不偿失的。那有没有一种更好的方法来解决这个问题呢?有的,那就是动态代理
。
jdk原生给我们提供了动态代理API:
static Object java.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
ClassLoader loader,:指定当前目标对象使用类加载器
Class<?>[] interfaces,:目标对象实现的接口的类型
InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
使用jdk动态代理实现:
RequestProcessor requestProcessor = new DefaultRequestProcessor();
RequestProcessor proxyInstance = (RequestProcessor) Proxy.newProxyInstance(requestProcessor.getClass().getClassLoader(), requestProcessor.getClass().getInterfaces(), new java.lang.reflect.InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("请求前检查参数,白名单等");
// method.invoke就是执行被代理对象的方法
Object ret = method.invoke(requestProcessor, args);
System.out.println("请求结束对请求结果压缩,加密,添加标识等操作");
return ret;
}
});
proxyInstance.process();
如果想对jdk动态代理原理了解比较清楚的话,可以参考我的另一篇博客:动手实现jdk动态代理