1 AOP简介

AOP:Aspect-Oriented Programming,面向切面编程

  • 切入点(PointCut): 一组连接点的集合,它定义了切面的哪些方法应该被执行(即在哪些类、哪些方法上切入),通常是一个正则表达式
  • 执行点(JoinPoint): 通过PointCut选取出来的集合中的具体的一个执行点,如,方法调用、异常抛出或对象创建等
  • 通知(Advice): Aspect的具体行为,它定义了在JoinPoint上执行的操作。可分为前置(Before)、后置(After)、环绕(Around)、异常处理(Exception)和最终(Final)通知等
  • 切面(Aspect): 一个模块化单元,它封装了与横切关注点相关的行为。切面 = PointCut + Advice。即在什么时候、什么地方、做什么
  • 织入(Weaving): 把切面加入对象,并创建出代理对象的过程

2 Aspectj

see: https://github.com/eclipse-aspectj/aspectj/tree/master

2.1 通知(Advice)类型

顺序: @Around->@Before->方法执行->@AfterReturning/@AfterThrowing->@After->@Around

名称 说明
前置通知(@Before) PointCut前执行
后置通知(@AfterReturning) PointCut正常返回结果后执行(异常时不执行)
环绕通知(@Around) PointCut前和后都执行
异常通知(@AfterThrowing) PointCut抛出异常后执行(异常时执行)
最终通知(@After) PointCut后始终执行(正常和异常时都执行)

2.2 示例

see: https://github.com/hi-cooper/cz-tutorials/tree/main/aspectj-demo

2.2.1 pom

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.20.1</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.9.20.1</version>
</dependency>

2.2.2 业务方法

package com.taiwii.aspectjdemo.service;

import org.springframework.stereotype.Service;

@Service
public class UserService {

    public void print() {
        System.out.println("print()");
    }

    public void printThrowing() {
        System.out.println("printThrowing()");
        throw new RuntimeException("This is a RuntimeException");
    }
}

2.2.3 AOP配置

package com.taiwii.aspectjdemo.aop;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Parameter;
import java.util.Arrays;

@Slf4j
@Aspect
@Configuration
public class AOPConfig {
    @Pointcut("execution(* com.taiwii..service..*.*(..))")
    public void pointCutMethod() {
    }

    @Before("pointCutMethod()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        System.out.println("doBefore");
    }

    @AfterReturning("pointCutMethod()")
    public void doAfterReturning(JoinPoint joinPoint) throws Throwable {
        System.out.println("doAfterReturning");
    }

    @Around("pointCutMethod()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object result = null;
        try {
            System.out.println("before doAround");
            result = joinPoint.proceed();
            System.out.println("after doAround");
        } catch (Exception e) {
            System.out.println("after doAround Exception");
            throw e;
        }
        return result;
    }

    @AfterThrowing("pointCutMethod()")
    public void doAfterThrowing(JoinPoint joinPoint) throws Throwable {
        System.out.println("doAfterThrowing");
    }

    @After("pointCutMethod()")
    public void doAfter(JoinPoint joinPoint) throws Throwable {
        System.out.println("doAfter");
    }
}

2.2.4 测试类

package com.taiwii.aspectjdemo.service;

import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class UserServiceTest {
    @Autowired
    private UserService userService;

    @Test
    @Order(1)
    public void testPrint() {
        this.userService.print();
    }

    @Test
    @Order(2)
    public void testPrintThrowing() {
        this.userService.printThrowing();
    }
}

2.2.5 输出