springAOP - 教程
AOP基础
AOP:Aspect Oriented Programming(面向切面编程、面向方面编程),面向切面编程就是面向特定方法编程。
AOP的优势主要体现在以下四个方面:
- 减少重复代码:不需要在业务方法中定义大量的重复性的代码,只需要将重复性的代码抽取到AOP程序中即可。
- 代码无侵入:在基于AOP实现这些业务功能时,对原有的业务代码是没有任何侵入的,不需要修改任何的业务代码。
- 提高开发效率
- 维护方便
AOP是一种思想,而在Spring框架中,对这种思想进行了实现,那我们要学习的就是Spring AOP。
AOP核心概念
AOP进阶
通知类型
Spring AOP 通知类型
@Around
环绕通知,此注解标注的通知方法在目标方法前、后都被执行
@Before
前置通知,此注解标注的通知方法在目标方法前被执行
@After
后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
@AfterReturning
返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
@AfterThrowing
异常后通知,此注解标注的通知方法发生异常后执行
Spring提供了
@PointCut
注解,该注解的作用是将公共的切入点表达式抽取出来,需要用到时引用该切入点表达式即可。@Slf4j @Component @Aspect public class MyAspect1 { //切入点方法(公共的切入点表达式) @Pointcut("execution(* com.itheima.service.*.*(..))") private void pt(){} //前置通知(引用切入点) @Before("pt()") public void before(JoinPoint joinPoint){ log.info("before ..."); } }
通知顺序
- 当有多个切面的切入点都匹配到了目标方法,目标方法运行时,多个通知方法都会被执行。
- 执行顺序:
- 不同切面类中,默认按照切面类的类名字母排序:
- 目标方法前的通知方法:字母排名靠前的先执行
- 目标方法后的通知方法:字母排名靠前的后执行
- 用 @Order (数字) 加在切面类上来控制顺序
- 目标方法前的通知方法:数字小的先执行
- 目标方法后的通知方法:数字小的后执行
切入点表达式
一、execution
execution主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:
execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
其中带
?
的表示可以省略的部分
访问修饰符:可省略(比如: public、protected)
包名.类名: 可省略
throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
@Before("execution(void com.itheima.service.impl.DeptServiceImpl.delete(java.lang.Integer))")
可以使用通配符描述切入点
*
:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分..
:多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数切入点表达式的语法规则:
方法的访问修饰符可以省略
返回值可以使用
*
号代替(任意返回值类型)包名可以使用
*
号代替,代表任意包(一层包使用一个*
)使用
..
配置包名,标识此包以及此包下的所有子包类名可以使用
*
号代替,标识任意类方法名可以使用
*
号代替,表示任意方法可以使用
*
配置参数,一个任意类型的参数可以使用
..
配置参数,任意个任意类型的参数根据业务需要,可以使用 且(&&)、或(||)、非(!) 来组合比较复杂的切入点表达式。
二、@annotation
实现步骤:
编写自定义注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface LogOperation{ }
在业务类要做为连接点的方法上添加自定义注解
@Slf4j @Service public class DeptServiceImpl implements DeptService { @Autowired private DeptMapper deptMapper; @Override @LogOperation //自定义注解(表示:当前方法属于目标方法) public List list() { List deptList = deptMapper.list(); //模拟异常 //int num = 10/0; return deptList; }
3. 在切面类上
@Slf4j @Component @Aspect public class MyAspect6 { //针对list方法、delete方法进行前置通知和后置通知 //前置通知 @Before("@annotation(com.itheima.anno.LogOperation)") public void before(){ log.info("MyAspect6 -> before ..."); }