在学习《Java编程思想》的时候看到了动态代理,觉得很有意思,现在来做一下总结。
一、代理模式的定义
为其他对象提供一种以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在和目标对象之间起到中介的作用。
二、优点
三、模式结构
一个是真正的你要访问的对象(目标类),一个是代理对象,真正对象与代理对象实现同一个接口,先访问代理类再访问真正要访问的对象。
四、UML示意图
我们来看一个普通代理实现的例子:
1 //客户端接口 2 interface Interface { 3 4 void doSomething(); 5 6 void somethingElse(String arg); 7 } 8 9 //客户端实现类,就是执行业务逻辑的类10 class RealObject implements Interface {11 12 @Override13 public void doSomething() {14 // TODO Auto-generated method stub15 System.out.println("doSomething");16 }17 18 @Override19 public void somethingElse(String arg) {20 // TODO Auto-generated method stub21 System.out.println("somethingElse" + arg);22 }23 24 }25 26 //代理类27 class SimpleProxy implements Interface {28 29 private Interface proxied;30 31 public SimpleProxy(Interface proxied) {32 // TODO Auto-generated constructor stub33 this.proxied = proxied;34 }35 36 @Override37 public void doSomething() {38 // TODO Auto-generated method stub39 System.out.println("SimpleProxy doSomething");40 proxied.doSomething();41 }42 43 @Override44 public void somethingElse(String arg) {45 // TODO Auto-generated method stub46 System.out.println("SimpleProxy somethingElse "+arg);47 proxied.somethingElse(arg);48 }49 50 }51 52 public class SimpleProxyDemo{53 54 public static void consumer(Interface iface){55 iface.doSomething();56 iface.somethingElse("hello world");57 }58 59 public static void main(String[] args){60 consumer(new RealObject());61 System.out.println("/*****************************/");62 consumer(new SimpleProxy(new RealObject()));63 }64 }
运行结果如下:
1 doSomething2 somethingElsehello world3 /*****************************/4 SimpleProxy doSomething5 doSomething6 SimpleProxy somethingElse hello world7 somethingElsehello world
五、Java动态代理
Java的动态代理比代理的思想更向前迈进了一步,因为它可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上,它的工作揭示调用的类型并确定相应的对策。
接下来我们来看一下Java动态代理的例子:
1 interface Interface { 2 3 void doSomething(); 4 5 void somethingElse(String arg); 6 } 7 8 class RealObject implements Interface { 9 10 @Override11 public void doSomething() {12 // TODO Auto-generated method stub13 System.out.println("doSomething");14 }15 16 @Override17 public void somethingElse(String arg) {18 // TODO Auto-generated method stub19 System.out.println("somethingElse" + arg);20 }21 22 }23 24 //动态代理类25 class DynamicProxyHandler implements InvocationHandler{26 27 private Object proxied;28 29 public DynamicProxyHandler(Object proxied) {30 // TODO Auto-generated constructor stub31 this.proxied = proxied;32 }33 34 @Override35 public Object invoke(Object proxy, Method method, Object[] args)36 throws Throwable {37 // TODO Auto-generated method stub38 System.out.println("****proxy: " + proxy.getClass()+39 ", method: "+method+ ", args: "+ args);40 41 if(args != null){42 for (Object arg : args) {43 System.out.println(" "+ arg);44 }45 }46 47 return method.invoke(proxied, args);48 }49 }50 51 class SimpleDynamicProxy{52 53 public static void consumer(Interface iface){54 iface.doSomething();55 iface.somethingElse("hello world");56 }57 58 public static void main(String[] args){59 RealObject real = new RealObject();60 consumer(real);61 62 System.out.println("/*******************************/");63 64 Interface proxy = (Interface)Proxy.newProxyInstance(65 Interface.class.getClassLoader(), 66 new Class[]{Interface.class},67 new DynamicProxyHandler(real));68 69 consumer(proxy);70 71 }72 73 }
运行结果如下:
1 doSomething2 somethingElsehello world3 /*******************************/4 ****proxy: class com.sun.proxy.$Proxy0, method: public abstract void Interface.doSomething(), args: null5 doSomething6 ****proxy: class com.sun.proxy.$Proxy0, method: public abstract void Interface.somethingElse(java.lang.String), args: [Ljava.lang.Object;@756095fc7 hello world8 somethingElsehello world
通过调用静态方法Proxy.newProxyInstance()可以创建动态代理。这个方法需要得到一个类加载器(你通常可以从已经被加载的对象中获取其类加载器,然后传递给它),一个你希望该代理实现的接口列表(不是类或者抽象类),以及InvocationHandler接口的一个实现。动态代理可以将所有调用重定向到调用处理器,因此通常会向调用处理器的构造器传递一个“实际”对象的引用,从而使得调用处理器执行其中介任务时,可以将请求转发。
invoke()方法传递进来了代理对象,以防你需要区分请求的来源,但是在许多情况下,你并不关心这一点。然而,在invoke()内部,在代理上调用方法时需要格外小心,因为接口的调用将被重定向为对代理对象的调用。
通常,你会执行被代理的操作,然后使用Method.invoke()将请求转发给 被代理对象,并传入必需的参数。这初看起来可能有些受限,就像你只能执行泛化操作一样。但是,你可以通过传递其他的参数,来过滤某些方法的调用。