码迷,mamicode.com
首页 > 其他好文 > 详细

代理模式:动态代理

时间:2020-09-17 13:39:54      阅读:27      评论:0      收藏:0      [点我收藏+]

标签:对象   system   invoke   final   代理模式   a*   执行器   输出   oca   

1. 为什么要用动态代理

对于一个类的方法

public class Calculator {
    public void add(int i,int j){
        System.out.println("add方法调用,参数为"+i+","+j);
        System.out.println(i + j);
        System.out.println("add方法结束,结果为"+(i+j));
    }
    public void sub(int i, int j){
        System.out.println(i - j);
    }
}

我们想打印日志信息,或者保存日志信息。我们需要在方法执行的前后加上打印输出或者日志记录的代码,如上的add方法中
但是,当我们如果某天我们不想要记录日志信息,我们需要手动删除日志语句。

2. 于是我们可以使用动态代理

  • 使用某一个类,“包装”Calculator,并且在它执行前,执行日志代码,好像听起来很像装饰器模式哈

1. 首先我们需要一个接口

public interface Calculator {
    public int add(int a, int b);
    public int sub(int a, int b);
    public int mul(int a, int b);
    public int div(int a, int b);
}

2. 然后对该接口进行实现

public class MyMathCalculator implements Calculator {
    public int add(int a, int b) { return a+b; }
    public int sub(int a, int b) { return a-b; }
    public int mul(int a, int b) { return a*b; }
    public int div(int a, int b) { return a/b; }
}

3. 然后就是最重要的代理类了

主要是使用java的Proxy.newProxyInstance()来创建动态代理对象。
主要用到了反射的知识奥,8会的建议去看一看发射。

public class CalculatorProxy{
    public static Calculator getProxy(final Calculator calculator){
        
        ClassLoader classLoader = calculator.getClass().getClassLoader();
        Class<?>[] classes = calculator.getClass().getInterfaces();
        
        //方法执行器。帮我们目标对象执行目标方法-----匿名接口对象
        InvocationHandler invocationHandler = new InvocationHandler() {
            /**
             * @param proxy 代理对象;给jdk使用,任何时候都不要动这个对象
             * @param method 当前将要执行的目标对象的方法
             * @param args 这个方法调用时外界传,入的参数值
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable             {
                
                //利用反射执行目标方法
                //目标执行后的返回值
                System.out.println("动态代理执行");
                Object result = method.invoke(calculator, args);
                
                //返回值必须返回出去外界才能拿到真正执行后的返回值
                return result;
            }
        };
        //Proxy为目标对象创建代理对象
        Object o = Proxy.newProxyInstance(classLoader, classes, invocationHandler);
        return (Calculator) o;
    }
}

4.使用

    public static void main(String[] args) {
        //普通调用
        Calculator calculator = new CalculatorImpl();
        calculator.add(2,3);
        System.out.println(calculator.getClass());
        //代理调用
        Calculator proxy = CalculatorProxy.getProxy(calculator);
        proxy.add(1,2);
        System.out.println(proxy.getClass());
    }

疑惑:

  1. 为什么要一个Calculator的接口
    因为对于代理对象来说,我们可以通过上面使用中间的getClass看到,代理对象的类型是属于

class com.sun.proxy.$Proxy0
而我们的对象是
class com.xj.day0904Proxy.CalculatorImpl

如果没有接口存在,可以看出两个类型是没有任何关系的
但是有了这个接口后,两个类都实现了同一个接口,此时,代理类也就具有了add,sub等等的方法;
之后代理类调用add方法后,就会去执行被代理对象的各种方法,并且在执行前后进行日志等操作

代理模式:动态代理

标签:对象   system   invoke   final   代理模式   a*   执行器   输出   oca   

原文地址:https://www.cnblogs.com/flower1360/p/13616472.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有 京ICP备13008772号-2
迷上了代码!