应用场景
代理模式,英文名Proxy Pattern
该模式用一个代理类代替原始类进行工作
使用这种模式,一般是出于以下几种目的
- 对原始类的功能进行增强、拦截、修改
- 控制原始类的访问权限
- 分担原始类的工作负荷
凡是能起到代理工作作用的方式,都可以认为是代理模式,所以它的实现也是多种多样的
我们现在只列举几种主流的实现形式
普通代理
代理类包装了一个原始类,并且实现了和原始类一样的接口,但代理类调用原始类来处理工作
public interface IAction {
void handle();
}
public class Action implements IAction {
@Override
public void handle() {}
}
public class ProxyAction implements IAction {
private Action action = new Action();
@Override
public void handle() {
System.out.print("before handle");
action.handle();
System.out.print("after handle");
}
}
强制代理
原始类不执行工作,强制要求使用代理类来执行工作
比如开发组长和普通开发都属于开发,但是开发组长就可以强制要求通过普通开发来完成某些工作
public interface IAction {
void handle();
}
public class Action implements IAction {
private IAction proxy = null;
public IAction getProxy() {
this.proxy = new ProxyAction(this);
return this.proxy;
}
@Override
public void handle() {
throw new RuntimeException("please use proxy to handle work");
}
}
public class ProxyAction implements IAction {
private final IAction origin;
public ProxyAction(IAction origin) {
this.origin = origin;
}
@Override
public void handle() {
}
}
动态代理
在代码运行阶段,通过代码动态创建代理对象,而不是在编码阶段,就已经定义好了代理类
这需要编程语言的支持,并不是所有语言都支持这种特性
Java语言是通过Proxy和InvocationHandler这两个类来实现动态代理功能的
public interface IAction {
void handle();
}
public class Action implements IAction {
@Override
public void handle() {
System.out.print("handle");
}
}
public class InvokeHandler implements InvocationHandler {
private Object obj;
public InvokeHandler(Object obj) {
this.obj = obj;
}
@Override
@SneakyThrows
public Object invoke(Object proxy, Method method, Object[] args) {
if (obj instanceof IAction && method.getName().equals("handle")) {
System.out.print("before handle");
Object rst = method.invoke(obj, args);
System.out.print("after handle");
return rst;
}
return null;
}
}
public class APP {
public static void main(String[] args) {
IAction action = new Action();
InvokeHandler handler = new InvokeHandler(action);
IAction proxy = (IAction) Proxy.newProxyInstance(action.getClass().getClassLoader(), new Class[]{IAction.class}, handler);
proxy.handle();
}
}
Java动态代理实现原理
可以看到,Proxy.newProxyInstance总共接收了三个参数
ClassLoader loader, Class[] interfaces, InvocationHandler handler
loader传入原始对象的ClassLoader即可,这个仅仅是用来创建动态类型用的
具体通过哪个class获取ClassLoader并没有区别,一般用户自定义的class,最终获得的ClassLoader都是同一个
Proxy根据interfaces,来动态创建一个新的类型,这个类型会继承Proxy,并实现interfaces指定的全部接口
当类型定义完成之后,下一步就是动态类中的函数如何实现
这个是通过InvocationHandler,由用户手动去指定的