使用代理(Proxy)实现Spring的AOP功能

一、场景

现在有一个需求,比如,现在有加减乘除四个方法,要求在执行这行方法的前后,分别做日志打印,要求打印出入参和运算结果。

二、基本实现

1、加减乘除接口
public interface ArithmeticCalculator {

    int add(int i,int j);
    int sub(int i,int j);
    int mul(int i, int j);
    int div(int i, int j);
}
2、接口实现
public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {

    @Override
    public int add(int i, int j) {
        System.out.println("the method add begins with [" + i +"," + j + "]");
        int result = i + j;
        System.out.println("the method ends with " +result);
        return result;
    }

    @Override
    public int sub(int i, int j) {
        System.out.println("the method add begins with [" + i +"," + j + "]");
        int result = i - j;
        System.out.println("the method ends with " +result);
        return result;
    }

    @Override
    public int mul(int i, int j) {
        System.out.println("the method add begins with [" + i +"," + j + "]");
        int result = i * j;
        System.out.println("the method ends with " +result);
        return result;
    }

    @Override
    public int div(int i, int j) {
        System.out.println("the method add begins with [" + i +"," + j + "]");
        int result = i / j;
        System.out.println("the method ends with " +result);
        return result;
    }

}
3、测试方法
public class Main {

    public static void main(String[] args) {
        ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorLoggingImpl();
        arithmeticCalculator.add(2, 3);
    }
}
4、输出结果:

这里写图片描述
从上面代码可以看出,日志的输出完全和运算方法耦合在一起,如果现在有需求改变,要求在方法执行前后,再加入执行时间,这样的话,就得一行一行的改代码,非常不利于维护。下面采用代理模式,来解决上述问题。

三、采用代理模式实现上述方法

1、加减乘除的接口与上面一样,保持不变,此处略。
2、加减乘除的接口实现,去掉上面的日志记录,如下:
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;
    }

}
3、编写代理类
public class ArithmeticCalculatorLogginProxy {

    //要代理的对象
    private ArithmeticCalculator target;

    public ArithmeticCalculatorLogginProxy(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() {

            /*
             *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 " + result);
                return result;
            }
        };

        proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
        return proxy;
    }
}
4、测试代码
public class Main {

    public static void main(String[] args) {

        ArithmeticCalculator target = new ArithmeticCalculatorImpl();
        ArithmeticCalculator proxy = new ArithmeticCalculatorLogginProxy(target).getLoggingProxy();

        int result = proxy.add(2, 3);
        System.out.println("-->" + result);

        result = proxy.mul(2, 4);
        System.out.println("-->" + result);
    }
}
5、输出结果:

这里写图片描述

四、总结

1、使用代理模式,就可以将日志的输出抽离出来,实现了解耦,但此种方法会要求对代理模式有很好的认识,在实际项目中,也很难写出这样的代码。所以,会在下面使用Spring的AOP来实现日志输出。

猜你喜欢

转载自blog.csdn.net/zxd1435513775/article/details/80762835
今日推荐