动态代理(JDK实现)

来源:互联网 发布:正规的淘宝模特兼职 编辑:程序博客网 时间:2024/06/01 23:13

代理是基本的设计模式之一,代理通常充当着中间人的角色。


一个代理的简单示例:

/** * 代理结构的简单示例 * */interface Interface {    void doSomething();    void somethingElse(String arg);}class RealObject implements Interface {    public void doSomething() {        System.out.println("doSomething");    }        public void somethingElse(String arg) {        System.out.println("somethingElse " + arg);    }}class SimpleProxy implements Interface {    private Interface proxied;        public SimpleProxy(Interface proxied) {        this.proxied = proxied;    }        public void doSomething() {        System.out.println("SimpleProxy doSomething");        proxied.doSomething();    }        public void somethingElse(String arg) {        System.out.println("SimpleProxy somethingElse " + arg);        proxied.somethingElse(arg);    }    }public class SimpleProxyDemo {        public static void consumer(Interface iface) {        iface.doSomething();        iface.somethingElse("bonobo");    }        public static void main(String[] args) {        consumer(new RealObject());        consumer(new SimpleProxy(new RealObject()));    }}

    因为consumer()接受的是Interface,所以它无法知道正在获得的到底是RealObject还是SimpleProxy,因为这二者都实现了Interface。但是SimpleProxy已经被插入到了客户端和RealObject之间,因此它会执行操作,然后调用RealObject上相同的方法。

    如果你希望跟踪对RealObject中的方法调用,或者希望度量这些调用的开销,这些代码肯定不希望将其合并到应用中的代码,因此代理使得很容易地添加或移除它们(降低耦合度,业务逻辑与日志、事务、异常、开销等逻辑区分开)。

    Java的动态代理比代理的思想更向前迈进了一步,因为他可以动态地创建代理并动态地处理对所代理方法的调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上。

    这样代理类不用因为新增一个接口就得加一个,动态代理实现了多个接口及多个方法都能用一个调用处理器来处理代理。

    可以通过调用静态方法 Proxy.newProxyInstance()创建动态代理。

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 通过调用 Proxy.newProxyInstance()方法可以实现动态代理 * @author cmdsm *  * */// 实现调用处理器class DynamicProxyHandler implements InvocationHandler {private Object proxied;public DynamicProxyHandler(Object proxied) {this.proxied = proxied;}/** * 动态代理可以将所有调用重定向到调用处理器 *  * invoke()方法传递进来了代理对象proxy,以防需要区分请求的来源, * 但是许多情况下并不需要关心这一点。 * 在invoke()内部,在代理上调用方法时需要格外当心,因为对接口的调用将被重定向为对代理的调用 */public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("**** proxy: " + proxy.getClass() + ". method " + method + ". args: " + args);if (args != null) for (Object arg : args) System.out.println(" " + arg);return method.invoke(proxied, args);}}public class SimpleDynamicProxy {public static void consumer(Interface iface) {iface.doSomething();iface.somethingElse("bonobo");}public static void main(String[] args) {RealObject real = new RealObject();consumer(real);// Insert a proxy and call againInterface proxy = (Interface) Proxy.newProxyInstance(// 需要一个类加载器,从哪个类获取都可以,一般从已加载的类获取Interface.class.getClassLoader(), // 需要希望该代理实现的接口列表(不是类或抽象类)new Class[]{Interface.class}, // 需要一个InvocationHandler(调用处理)接口的实现new DynamicProxyHandler(real));consumer(proxy);}}


可以通过传递其他参数,来过滤某些方法调用

import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * 动态代理 过滤某些方法的调用 * @author cmdsm * */class MethodSelector implements InvocationHandler {private Object proxied;public MethodSelector(Object proxied) {this.proxied = proxied;}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (method.getName().equals("interesting"))System.out.println("Proxy detected the interesting method");return method.invoke(proxied, args);}}interface SomeMethods {void boring1();void boring2();void interesting(String arg);void boring3();}class Implementation implements SomeMethods {public void boring1() {System.out.println("boring1"); }public void boring2() {System.out.println("boring1"); }public void interesting(String arg) {System.out.println("interesting " + arg);}public void boring3() {System.out.println("boring1"); }}public class SelectingMethods {public static void main(String[] args) {SomeMethods proxy = (SomeMethods) Proxy.newProxyInstance(SomeMethods.class.getClassLoader(), new Class[]{SomeMethods.class}, new MethodSelector(new Implementation()));proxy.boring1();proxy.boring2();proxy.interesting("bonobo");proxy.boring3();}}



输出:



摘自Java编程思想