spring基础知识 (17):AOP基础

为什么要使用AOP

每个技术的诞生都是为了问题的,而AOP是为了解决什么问题的呢?

发现问题
假设我们要实现一个计算器功能,要求
- 能够实现基本的加减乘除计算功能
- 要求实现日志功能
实现上面的需求比较直接简单的方法是:在每个计算功能核心代码中都写入日志输出处理。

  • 写一个计算器接口
package com.spring.proxy;

public interface Calculator {

    int add(int i,int j);
    int sub(int i,int j);
}
  • 实现类:
package com.spring.proxy;

public class CalculatorImpl implements Calculator{

    @Override
    public int add(int i, int j) {
        System.out.println("Log:method add begin:"+i+" and "+j);
        int result = i + j;
        System.out.println("Log:method add end:"+i+" and "+j);
        return result;
    }

    @Override
    public int sub(int i, int j) {
        System.out.println("Log:method div begin:"+i+" and "+j);
        int result = i - j;
        System.out.println("Log:method div end:"+i+" and "+j);
        return result;
    }

}
  • 问题
    上面代码实现了我们的日志需求,但是这种实现方式很是繁琐。而且日志模块和核心代码混杂在一起,使得后期维护也不是很方便。显然不是我们想要的。

使用动态代理解决以上问题

  • 核心代码块保持纯净,只负责自己的功能就行:
package com.spring.proxy;

public class CalculatorImpl implements Calculator{

    @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;
    }

}
  • 代理类
package com.spring.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;


public class CalculatorProxy{

    //引入被代理对象
    private Object target;

    public CalculatorProxy(Object target) {
        this.target = target;
    }



    public Object getCalcultorProxy() {

        Object proxy = null;
        //代理对象由哪个类加载器加载
        ClassLoader loader = target.getClass().getClassLoader();
        //代理对象的类型,即其中有哪些方法
        Class[] interfaces = target.getClass().getInterfaces();
        //处理方法
        InvocationHandler h = new InvocationHandler(){
             /**
             * proxy:正在返回的代理的对象,一般不去使用它
             * method: 被调用的方法
             * args: 被调用方法的参数
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                String methodName = method.getName();
                //日志
                System.out.println("Log:method "+methodName+" begin:"+Arrays.asList(args));
                //执行方法
                Object result = method.invoke(target, args);
                //日志
                System.out.println("Log:method "+methodName+" end:"+Arrays.asList(args));

                return result;
            }
        };

        //创建代理对象
        proxy =  Proxy.newProxyInstance(loader, interfaces, h);

        return proxy;
    }


}
  • 测试:
Calculator target = new CalculatorImpl();

Calculator proxy = (Calculator) new CalculatorProxy(target).getCalcultorProxy();
int result = proxy.add(1, 2);
System.out.println("-->"+result);
result = proxy.sub(2, 1);
System.out.println("-->"+result);

这里写图片描述

  • 成功实现日志功能,而不影响Calcultor的核心实现代码
  • 但是这样还是相对麻烦,而且对程序员要求会很高。
  • 使用AOP可以很方便的解决上述问题。

认识AOP

  • AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面向对象编程) 的补充.
  • AOP 的主要编程对象是切面(aspect), 而切面模块化横切关注点. 在应用 AOP 编程时, 仍然需要定义公共功能, 但可以明确的定义这个功能在哪里, 以什么方式应用, 并且不必修改受影响的类.
    这样一来横切关注点就被模块化到特殊的对象(切面)里.
  • AOP 的好处: 每个事物逻辑位于一个位置, 代码不分散, 便于维护和升级 业务模块更简洁, 只包含核心业务代码.

上面那个是比较官方的解释,有点难理解,下面用图解说明:
这里写图片描述
简单认识下图中的一些专业术语:

  • 横切关注点:需要实现的一些附加功能,比如上面的日志功能等。
  • 切面(Aspect): 将横切关注点抽取出来定义成单独的模块。
  • 目标(Target): 需要添加附加功能的对象

猜你喜欢

转载自blog.csdn.net/abc997995674/article/details/80298029