java 代理模式
代理(proxy)模式:指目标对象给定代理对象,并由代理对象代替真实对象控制客户端对真实对象的访问。
代理模式模式有以下角色:
抽象主题(subject)角色:声明真实主题和代理主题的共同接口。
真实主题(real subject)角色:定义代理对象需要代理的真实对象。
代理主题(proxy subject)角色:代替真实对象来控制对真实对象的访问,代理对象持有真实对象的应用,从而可以随时控制客户端对真实对象的访问。
代理模式结构类图:
代理模式在java里面很常见,在开源框架里如spring,mybatis等里面大量使用。现实生活中也很常见,比如我们访问facebook主站,常会选择一些代理,通过代理访问facebook。代理分静态代理和动态代理,java对动态代理有很好的支持,提供了InvocationHandler接口和Proxy类。
java API 对
InvocationHandler接口和Proxy类的介绍:
Proxy
提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。创建某一接口 Foo
的代理:
InvocationHandler handler = new MyInvocationHandler(...); Class proxyClass = Proxy.getProxyClass( Foo.class.getClassLoader(), new Class[] { Foo.class }); Foo f = (Foo) proxyClass. getConstructor(new Class[] { InvocationHandler.class }). newInstance(new Object[] { handler });
或使用以下更简单的方法:
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);
动态代理类(以下简称为代理类)是一个实现在创建类时在运行时指定的接口列表的类,该类具有下面描述的行为。 代理接口 是代理类实现的一个接口。 代理实例 是代理类的一个实例。 每个代理实例都有一个关联的调用处理程序 对象,它可以实现接口 InvocationHandler
。通过其中一个代理接口的代理实例上的方法调用将被指派到实例的调用处理程序的 Invoke
方法,并传递代理实例、识别调用方法的 java.lang.reflect.Method
对象以及包含参数的 Object
类型的数组。调用处理程序以适当的方式处理编码的方法调用,并且它返回的结果将作为代理实例上方法调用的结果返回。InvocationHandler
是代理实例的调用处理程序 实现的接口。每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke
方法。
这里举个好理解的例子:公司项目部需要CEO签署一个文件,项目负责人会把文件交给CEO助理,助理会收文件,等到CEO回来后递CEO,CEO签署后交给助理,助理收好交给项目负责人。这个过程中项目负责人其实不知道是否真的是CEO签署的文件,有可能是助理打印的CEO的签名到文件上。这样助理就是一个代理角色,代替CEO处理事务。静态代理类图如下:
代码如下:
- package proxy;
- /**
- *
- *作者:alaric
- *时间:2013-7-24下午10:44:12
- *描述:抽象主题
- */
- public interface Leader {
- public void sign();
- }
- package proxy;
- /**
- *
- *作者:alaric
- *时间:2013-7-24下午10:45:05
- *描述:ceo 真实主题
- */
- public class CEO implements Leader {
- @Override
- public void sign() {
- System.out.println("CEO签文件");
- }
- }
- package proxy;
- /**
- *
- *作者:alaric
- *时间:2013-7-24下午10:45:25
- *描述:代理主题
- */
- public class Assistant implements Leader{
- private Leader leader ;
- public Assistant(Leader leader) {
- super();
- this.leader = leader;
- }
- @Override
- public void sign() {
- System.out.println("递给领导");
- leader.sign();
- System.out.println("装入袋子,送出");
- }
- }
- package proxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- /**
- *
- *作者:alaric
- *时间:2013-7-24下午10:46:04
- *描述:动态代理的Handler
- */
- public class AssistantHandler implements InvocationHandler {
- /**
- * 目标对象
- */
- private Object targetObject;
- /**
- *
- *作者:alaric
- *时间:2013-7-24下午10:46:59
- *描述:创建代理对象 这段也可以不在此类,也可以放在客户端里面
- */
- public Object createProxy(Object targetOjbect){
- this.targetObject = targetOjbect;
- return Proxy.newProxyInstance(targetOjbect.getClass().getClassLoader(),
- targetOjbect.getClass().getInterfaces(), this);
- };
- /**
- * 此方法为必须实现的,在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- Object result = null;
- System.out.println("递给领导");
- result = method.invoke(this.targetObject, args);
- System.out.println("装入袋子,送出");
- return result;
- }
- }
- package proxy;
- import java.lang.reflect.Proxy;
- /**
- *
- *作者:alaric
- *时间:2013-7-24下午10:44:37
- *描述:测试类 包括静态代理和动态代理
- */
- public class Client {
- /**
- * @param args
- */
- public static void main(String[] args) {
- //静态代理测试
- CEO ceo = new CEO();
- Leader leader1 = new Assistant(ceo);
- leader1.sign();
- System.out.println("=========================================");
- //动态代理测试,一些三种方式都可以获得动态代理对象
- AssistantHandler ah = new AssistantHandler(ceo);
- //Leader leader2 = (Leader) ah.createProxy(new CEO());
- //leader2.sign();
- //Leader leader3 = (Leader) Proxy.newProxyInstance(CEO.class.getClassLoader(),
- // ceo.getClass().getInterfaces(), ah);
- //leader3.sign();
- Leader leader4 = (Leader) Proxy.newProxyInstance(Leader.class.getClassLoader(),
- new Class[] { Leader.class },
- ah);
- leader4.sign();
- }
- }
运行结果如下:
递给领导
CEO签文件
装入袋子,送出
=========================================
递给领导
CEO签文件
装入袋子,送出
通过上面例子和代码可以看出,动态代理显得更为灵活,实际过程中动态代理也较为常用。
欢迎关注公众号:Java后端技术全栈