第三章、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);
    }
原文地址:https://www.cnblogs.com/jdy1022/p/13678081.html