1 什么是AOP?

Aspect Oriented Programming ,即面向切面编程

  • AOP是对面向对象编程的一个补充;
  • 它的目的是将复杂的需求分解为不同的切面,将散布在系统中的公共功能集中解决;
  • 它的实际含义是在运行时将代码切入到类的指定方法、指定位置上,将不同方法的同一个位置抽象为一个切面对象,并对该对象进行编程。

下面是AOP的一个示意图

java 切片编程 java切面_java 切片编程

2 AOP的有点和概念

2.1 优点

  • 降低模块之间的耦合度;
  • 使系统更容易扩展;
  • 更好的代码复用;
  • 非业务代码更加集中,不分散,便于统一管理;
  • 业务代码更加简洁纯粹,不掺杂其他的代码影响。

2.2 常见概念

  • 切面:横切关注点,被模块化的抽象对象;
  • 通知:切面对象完成的工作(非业务代码);
  • 目标:被通知的对象(即被横切的对象);
  • 代理:切面、通知、目标混合之后的对象;
  • 连接点:通知要插入业务代码的具体位置(如Spring实现中的JoinPoint);
  • 切点:AOP通过切点定位到连接点。

3 使用注解方式实现Spring AOP的使用

3.1 添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>2.3.7.RELEASE</version>
</dependency>

3.2 定义实体类,实现方法

3.3 添加切面(创建切面类)

java 切片编程 java切面_AOP_02

java 切片编程 java切面_方法名_03

/**
 * @ClassName: DemoAspect
 * @Description: 切面类
 * @Date: 2022/9/21 9:00
 */
//Aspect注解声明了这是一个切面类
//Component注解把切面类交给了IoC容器进行管理
@Aspect
@Component
public class DemoAspect {

    @Autowired
    private DemoEntityService demoEntityService;

    @Pointcut("execution( * com.demo.service.impl.DemoEntityServiceImpl.submitMain(..))"
            + "||execution( * com.demo.demo1.service.impl.Demo1EntityServiceImpl.saveInfo(..))"
            + "||execution( * com.demo.demo2.service.impl.Demo2EntityServiceImpl.submitReturnData(..))")
    public void demoPointCut() {
    }

    /**
     * @description 切点方法返回之后执行
     * @date 2022/8/3 13:24
     * AfterReturning中的pointcut这样写代表在submitMain、saveInfo、submitReturnData方法返回后都会执行doAfterReturning方法中的代码
     **/
    @AfterReturning(returning = "result", pointcut = "demoPointCut()")
    public void doAfterReturning(Object result) throws Exception {
        System.out.println("切点方法返回后执行");
        demoEntityService.demoMethod(result);
    }

    /**
     * @description 切点方法开始前执行
     * @date 2022/8/3 13:24
     * Before中的pointcut这样写代表在submitMain、saveInfo、submitReturnData方法返回后都会执行doAfterReturning方法中的代码
     **/
    @Before("demoPointCut()")
    public void doBefore(JoinPoint joinPoint) throws Exception {
        //joinPoint参数传递了方法的基本信息
        System.out.println("切点方法开始前执行");

        //获取方法名
        //joinPoint.getSignature()获得方法的Method对象,随后的getName()获得方法名
        String name = joinPoint.getSignature().getName();

        //获取参数
        //将参数数组转换为字符串
        //joinPoint的getArgs()获得方法的参数列表,以String类型存储
        String args = Arrays.toString(joinPoint.getArgs());

        //切面要执行的非业务代码
        System.out.println(name + "方法的参数是" + args);
    }

    /**
     * @description 切点方法执行后执行
     * @date 2022/8/3 13:24
     * Before中的pointcut这样写代表在submitMain、saveInfo、submitReturnData方法返回后都会执行doAfterReturning方法中的代码
     **/
    @After("demoPointCut()")
    public void doAfter(JoinPoint joinPoint) throws Exception {
        //joinPoint参数传递了方法的基本信息
        System.out.println("切点方法执行后执行");

        //获取方法名
        //joinPoint.getSignature()获得方法的Method对象,随后的getName()获得方法名
        String name = joinPoint.getSignature().getName();

        //切面要执行的非业务代码
        System.out.println(name + "方法执行完毕");
    }

    //环绕增强
    @Around("demoPointCut()")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("前环绕");
        //执行其切点方法
        pjp.proceed();
        System.out.println("后环绕");
    }
}

View Code

3.4 补充说明

3.4.1 AOP开发注解的类型

其中,通知的配置语法:@通知注解(“切点表达式")

java 切片编程 java切面_方法名_04

各种增强的执行顺序分别是:

前环绕增强->前置增强->切点->后环绕增强->最终增强->后置增强

 After和After-returning的区别:

后置通知(After):表示在目标方法执行完成后执行的通知功能,即使在执行目标方法出现异常,也照常执行这个逻辑。

返回通知(After-returning)表示目标方法正常执行完成后置的通知功能,如果目标方法执行过程中出现异常,那么这个通知的逻辑就不执行。

切点表达式的一个格式语法如下:

格式:execution( [修饰符] 返回值类型 包名.类名.方法名 (参数) ),其中*表示任意类型,方法参数中 . . 表示任意的参数。

示例:

execution(public void aop.TargetImpl.run()) 表示 aop.TargetImpl类,修饰符为public,返回值、参数列表为空的run方法。
execution(void aop.TargetImpl.*()) 表示 aop.TargetImpl类,返回值、参数列表为空的任意方法。
execution(* aop…*(…)) 表示 aop包及其子包下的任意类,任意方法。

        https://blog.51cto.com/u_14020810/4851474#_101Spring_AOP_582