使用Proxy和InvocationHandler创建动态代理

来源:互联网 发布:大阪 香港知乎 编辑:程序博客网 时间:2024/05/17 00:00
    Proxy提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。如果在程序中为一个或多个接口动态的生成实现类,
就可以使用Proxy来创建动态代理类;如果需要为一个或多个接口动态地创建实例,也可以使用Proxy来创建动态代理实例。
    Proxy提供了如下两个方法来动态创建代理类和动态代理实例。
(1)    static Class<?> getProxyClass(ClassLoder loader, Class<?>...interfaces):创建一个动态代理类多对应的Class对象,该代理类实现将实现
interfaces所指定的多个接口。第一个ClassLoader参数指定生成动态代理类的类加载器。
(2)    static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h):直接创建一个动态代理对象,该代
理对象对象的实现类实现了interfaces指定的系列接口,执行代理对象的每个方法时都会替换成执行InvocationHandler对象的invoke方法。

实际上,即使采用第一个方法生成动态代理类之后,如果程序需要通过该代理类来创建对象,依然需要传入一个Invocationhandler对象。也就
是说,系统生成的每个代理对象都有一个与之关联的Invocationhandler对象。例如下面的代码:

// 创建一个InvocationHandler对象,其中MyInvocationHandler是实现InvocationHandler接口的类InvocationHandler handler = new MyInvocationHandler();// 使用Proxy生成一个动态代理类proxyClassClass proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), new Class[]{Foo.class});// 获取proxyClass类中带有一个InvocationHandler参数的构造器Constructor ctor = proxyClass.getConstructor(new Class[]{Invocationhandler.class});// 调用ctor的newInstance方法来创建动态实例Foo f = (Foo) ctor.newInstance(new Object[]{Handler});


    下面程序示范了使用Proxy和InvocationHandler来生成动态代理对象。其目的是:对需要代理的对象的每个方法的开始和结束打印一行日志
信息:
ArithmeticCalculatorloggingImpl.java:

package com.yu.spring.aop.helloworld;public class ArithmeticCalculatorImpl implements ArithmeticCalculator {    @Override    public int add(int i, int j) {        int result = i + j;        return result;    }    @Override    public int sub(int i, int j) {        int result = i - j;        return result;    }    @Override    public int mul(int i, int j) {        int result = i * j;        return result;    }    @Override    public int div(int i, int j) {        int result = i / j;        return result;    }}


ArithmeticCalculatorLoggingProxy.java:

package com.yu.spring.aop.helloworld;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;import java.util.Arrays;public class ArithmeticCalculatorLoggingProxy {    // 要代理的对象    private ArithmeticCalculator target;    public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {        this.target = target;    }    public ArithmeticCalculator getLoggingProxy(){        ArithmeticCalculator proxy = null;        // 代理对象由哪一个类加载器负责加载        ClassLoader loader = target.getClass().getClassLoader();        // 代理对象的类型,即其中有哪些方法        Class[] interfaces = new Class[]{ArithmeticCalculator.class};        // 当调用代理对象其中的方法时,该执行的代码        InvocationHandler h = new InvocationHandler(){            /**             * 执行动态代理对象的所有方法时,都会替换成执行如下的invoke方法,其中:             * proxy:正在返回的代理对象,一般情况下,在invoke方法中都不使用该对象             * method:正在被调用的方法             * args:调用方法时,传入的参数             */            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                String methodName = method.getName();                // 日志                System.out.println("the method " + methodName + " begins with " + Arrays.asList(args));                // 执行方法                Object result = method.invoke(target, args);                // 日志                System.out.println("The method " + methodName + " ends with " + Arrays.asList(args));                return result;            }        };        proxy =(ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);        return proxy;    }}

测试类Main.java:

package com.yu.spring.aop.helloworld;public class Main {    public static void main(String[] args) {//        ArithmeticCalculator ac = null;//        ac = new ArithmeticCalculatorImpl();        ArithmeticCalculator target = new ArithmeticCalculatorImpl();        ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy();        int result = proxy.add(1, 2);        System.out.println("-->" + result);        result = proxy.sub(4, 1);        System.out.println("-->" + result);        result = proxy.mul(2, 3);        System.out.println("-->" + result);        result = proxy.div(7, 3);        System.out.println("-->" + result);    }
测试结果:


0 0
原创粉丝点击