在学习Spring Framework的时候接触过AOP的相关内容—>Spring基础学习 - AOP机制
· f10@t's blog (f10at.cn)。
但是当时没有记录使用注解的方式,且仅学习了Advisor没有了解其与Aspect的联系和区别,遂补一个坑。
喜欢我昆明池吗?
基于注解编写切面
其实整个过程还是比较简单的,可以先入为主参考如下代码,其中定义了所有的五类通知类型。其他代码此处省略。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| package lzw.spring.springreview.aspect;
import lombok.extern.log4j.Log4j2; import lzw.spring.springreview.entity.People; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component;
@Aspect @Log4j2 @Component public class PeopleServiceAspect {
@Pointcut(value = "execution(* lzw.spring.springreview.service.impl.PeopleServiceImpl.getPeople(String, Integer))") public void pointcutDef() { }
@Before(value = "pointcutDef()") public void beforeGetPeople(JoinPoint joinPoint) { log.info(joinPoint.getSignature().getName() + " 执行前"); }
@After(value = "pointcutDef()") public void afterGetPeople(JoinPoint joinPoint) { log.info(joinPoint.getSignature().getName() + " 执行后"); }
@AfterReturning(value = "pointcutDef()", returning = "peopleToReturn") public void afterReturning(JoinPoint joinPoint, People peopleToReturn) { log.info(joinPoint.getSignature().getName() + "的返回值是" + peopleToReturn.toString()); }
@AfterThrowing(value = "pointcutDef()", throwing = "e") public void afterThrowing(JoinPoint joinPoint, Exception e) { log.info(joinPoint.getSignature() + "方法抛出异常了,异常是" + e); }
@Around(value = "pointcutDef()") public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { log.info(proceedingJoinPoint.getSignature().getName() + "环绕通知前"); Object toReturn = proceedingJoinPoint.proceed(); log.info(proceedingJoinPoint.getSignature().getName() + "环绕通知后"); return toReturn; } }
|
直接运行,从输出中就可以看到AOP的效果了:

从运行结果可以看出这五类通知和切入点函数的相对执行顺序:
环绕通知->前置通知->返回通知->后置通知->环绕通知。而异常通知则在切入点函数抛出异常时执行。
上述代码关键点:
- @Aspect:代表这是一个切面定义类;
- @Pointcut:定义一个切点,可以使用
execution
关键字来定义精细化的函数切入点位置;
- @Before:前置通知,
value
属性指定切点;
- @After:后置通知,
value
属性指定切点;
- @Around:环绕通知,
value
属性指定切点;
- @AfterReturning:返回通知,
value
属性指定切点,returning
属性指定返回对象变量名称;
- @AfterThrowing:异常通知,
value
属性指定切点,throwing
属性指定异常变量名称;
因而在使用Spring
AOP时,我们针对需要切面编程的服务单元编写一个切面,其中可以定义多个@Pointcut
注解的函数并配合execution
表达式实现精细化的切点定义,然后针对这些切点定义不同的通知类型。
exection
表达式的含义及上述例子中的表达式如下:

这里有一个区别,在之前的文章(Spring基础学习 - AOP机制
· f10@t's blog
(f10at.cn))中我学习的Spring切面实际上只是Advisor,即由一个切点和一个通知组成,可以理解为一个取了特值的Aspect。如上述代码所示,可以看到实际上对于一个真正的Aspect切面,我们是可以定义多个切点和多个通知的。
但其实Advisor也不是完全没用。个人理解在Spring中,我们也可以通过将不同Advisor注入到容器中,并根据不同需求使用ProxyFactoryBean将多个需要的Advisor组装成一个Aspect,从而提高代码的复用性。
参考学习
- 《Spring Boot进阶 原理、实战与面试题分析》——郑天民