• 第三章、AOP前奏


    一、提出问题

    1.1、情景:数学计算器

    要求

    • 执行加减乘除运算

    • 日志:在程序执行期间追踪正在发生的活动

    • 验证:希望计算器只能处理正数的运算 

    public class ArithmeticCalculatorImpl implements  ArithmeticCalculator{
        @Override
        public void add(int a, int b) {
            System.out.println("日志:The Method add begin ["+a+","+b+"]");
            int result = a+b;
            System.out.println("result = " + result);
        }
    }

    问题

    • 代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。

    • 代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。

    二、动态代理

    代理设计模式的原理使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

    2.1、动态代理的实现方式

    • 基于接口实现动态代理: JDK动态代理
    • 基于继承实现动态代理: Cglib、Javassist动态代理

    三、JDK实现动态代理

      使用jdk动态代理改进上面的日志打印

    3.1、动态代理概述

    Proxy类是动态代理的父类,用于生成代理类或者代理对象的。

    //生成代理对象
    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

    newProxyInstance方法中的三个参数

    • loader:类加载器对象,动态加载代理类

    • interfaces:目标类实现的所有接口,查看目标对象的方法都来自哪。

    • InvocationHandler接口类的对象

    动态代理整个过程是在newProxyInstance方法中的参数InvocationHandler中完成的,动态代理要做的业务逻辑放在InvocationHandler 的invoke方法中编写。

    public Object invoke(Object proxy, Method method, Object[] args)

    invoke方法中的三个参数

    • proxy:代理对象,调用代理方法会回过头调用invoke方法。

    • method:正在被调用的方法对象

    • args:正在被调用的方法参数

    代理对象调用代理方法会回过头调用invoke方法。

    3.2、实现动态代理步骤

    • 业务类
    @Service
    public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
        @Override
        public int add(int n, int m) {
            return n+m;
        }
    }
    • 自定义代理类
    public class CalculProxy {
        //第一步:目标对象
        private Object target;
        public CalculProxy(Object target) {
            this.target = target;
        }
        //第二步:获取代理对象
        public Object getObject(Object obj){
           return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
               //第三步:代理对象要做什么
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    String name = method.getName();
                    System.out.println("日志:The Method "+name+" begin "+ Arrays.toString(args));
                  ////相当于执行目标类中的方法(add sub 方法)
                    Object result = method.invoke(target, args);
                    System.out.println(name+":result = " + result);
                    return result;
                }
            });
        }
    }
    • 测试
    @Test
        public void test_method07() {
    
            //第一步:获取目标对象
            ArithmeticCalculatorImpl calculService = new ArithmeticCalculatorImpl();
            //第二步:获取代理对象
            CalculProxy calculProxy = new CalculProxy(calculService);
            ArithmeticCalculator proxy =(ArithmeticCalculator)calculProxy.getObject(calculService);
            proxy.add(1,2);
        }
  • 相关阅读:
    Balance_01背包
    4 Values whose Sum is 0_upper_bound&&ower_bound
    Newspaper Headline_set(upper_bound)
    lower_bound和upper_bound算法
    Blocks_DP&&矩阵快速幂
    All X_数的快速幂
    Training little cats_矩阵快速幂
    Raising Modulo Numbers_快速幂取模算法
    Defining Python Source Code Encodings
    Python ord(char)
  • 原文地址:https://www.cnblogs.com/jdy1022/p/13678081.html
Copyright © 2020-2023  润新知