AOP面向切面编程(实例)

创建一个具体的 BookService 示例,它有一个addBook()方法能添加书籍到数据库。

需要了解的基本知识:

@Aspect注解标明这是一个切面。

@Pointcut 定义了切点,用于标记方法。

joinPoint.getSignature().getName()返回的是被通知方法的简单方法名。

通知(Advice)的分类:

分为前置通知、后置通知、返回通知、异常通知和环绕通知。

  1. @Before:前置通知, 在方法执行之前执行

  2. @After:后置通知, 在方法执行之后执行

  3. @AfterReturning:返回通知, 在方法返回结果之后执行

  4. @AfterThrowing:异常通知, 在方法抛出异常之后

  5. @Around:环绕通知, 围绕着方法执行

其中环绕通知是前置通知、后置通知、异常通知、返回通知的任意组合。

AOP的一个实例如下:

1.模拟服务类 BookService

@Service
public class BookService {
    public String addBook(String bookName) {
        // 模拟添加书籍到数据库
        // 通常会有数据库的操作
        return "成功添加书籍:" + bookName;
    }
}

2.AOP的切面类,包含各种类型的通知

@Aspect
@Component
public class BookServiceAspect {

    // 定义一个切点,匹配 BookService 中所有的方法
    @Pointcut("execution(* com.example.BookService.*(..))")
    public void bookServicePointcut() {
    }

    @Before("bookServicePointcut()")
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("前置通知:方法 " + joinPoint.getSignature().getName() + " 即将调用...");
    }

    @After("bookServicePointcut()")
    public void afterAdvice(JoinPoint joinPoint) {
        System.out.println("后置通知:方法 " + joinPoint.getSignature().getName() + " 调用结束...");
    }

    @AfterReturning(pointcut="bookServicePointcut()", returning="result")
    public void afterReturningAdvice(JoinPoint joinPoint, String result){
        System.out.println("返回通知:方法 " + joinPoint.getSignature().getName() + " 成功执行,添加书籍结果:" + result);
    }

    @AfterThrowing(pointcut="bookServicePointcut()", throwing="error")
    public void afterThrowingAdvice(JoinPoint joinPoint, Throwable error){
        System.out.println("异常通知:方法 " + joinPoint.getSignature().getName() + " 执行出错:" + error.getMessage());
    }

    @Around("bookServicePointcut()")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知:方法 " + proceedingJoinPoint.getSignature().getName() + " 开始执行...");
        Object result;
        try {
            result = proceedingJoinPoint.proceed();
            System.out.println("环绕通知:方法 " + proceedingJoinPoint.getSignature().getName() + " 成功执行,添加书籍结果:" + result);
        } catch (Exception e) {
            System.out.println("环绕通知:方法 " + proceedingJoinPoint.getSignature().getName() + " 执行出错:" + e.getMessage());
            throw e;
        } finally {
            System.out.println("环绕通知:方法 " + proceedingJoinPoint.getSignature().getName() + " 执行结束...");
        }
        return result;
    }
}

在调用addBook()方法的时候,AOP的不同通知会在合适的时间段被触发,并打印出通知相关的信息。

注意:

1.@Pointcut("execution(* com.example.BookService.*(..))”)和@Pointcut("execution(* com.example.BookService.*.*(..))") 这两个切点表达式的区别在于对目标方法的匹配范围。

execution(* com.example.BookService.*(..)) 匹配 com.example.BookService 类中的所有方法,但不包括其内部的类的方法。也就是说,只匹配 com.example.BookService 类直接定义的方法。

execution(* com.example.BookService.*.*(..)) 则匹配 com.example.BookService 类及其内部的所有类中的所有方法。这包括了 com.example.BookService 类中定义的方法以及其内部类中定义的方法。

2.如果在切面类中同时定义了环绕通知和其他类型的通知(如前置通知,后置通知),并且它们的切点相同,那么在执行切点方法时,这些通知都会被触发。环绕通知中的逻辑会在其他通知之外额外执行,这可能会对程序的执行流程造成混淆。

你可能感兴趣的:(java,开发语言,spring,spring,boot)