AOP概述
AOP(Aspect Oriented Programming):⾯向切⾯编程,它是⼀种思想,它是对某⼀类事情的集中处理。
什么是SpringAOP?
⽽ AOP 是⼀种思想,⽽ Spring AOP 是⼀个框架,提供了⼀种对 AOP 思想的实现,它们的关系和 IoC 与 DI 类似。
为什要用 AOP?
在开发中,我们对于公共方法的处理分为三个阶段:
>>每个方法都去实现(初级)
>>抽取公共方法(中级)
>>采用AOP的方式,对代码进行无侵入式实现(高级)
因此,对于这种功能统⼀,且使⽤的地⽅较多的功能,在之前我们会抽取公共方法去实现,但是现在有更好的一个办法来处理这个问题,就是AOP。
也就是使⽤ AOP 可以扩充多个对象的某个能⼒,所以 AOP 可以说是 OOP(Object Oriented Programming,⾯向对象编程)的补充和完善。
AOP的作用?
提供声明式事务;允许用户自定义切面,保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。
将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。
Spring AOP的术语
名称 | 说明 |
---|---|
Joinpoint(连接点) | 应用执行过程中能够插入切面的一个点,这个点可以是方法调用时,抛出异常时,甚至修改字段时。切面代码可以利用这些点插入到应用的正常流程之中,并添加新的行为。 |
Pointcut(切入点) | Pointcut的作用就是提供一组规则 来匹配Join Point,给满足规则的Join Point 添加Advice。 |
Advice(通知) | 切面也有目标-他必须要完成的工作。在AOP中,切面的工作被称为通知。 |
Target(目标) | 指代理的目标对象 |
Weaving(植入) | 指把增强代码应用到目标上,生成代理对象的过程 |
Proxy(代理) | |
Aspect(切面) | 由切点(Pointcut)和通知(Advice)组成,既包含了横切逻辑的定义,也包含了连接点的定义。 |
AOP使用来对某一类事情进行集中处理的,那么处理事情,这个整体就是一个切面,处理事情的范围就是切点,范围中具体的事物就是连接点,怎么处理就是通知。
AOP的通知分类
通知又名拦截器,它定义了切面是做什么以及何时使用,即在某个特定的连接点上执行的动作,它是切面的具体实现。以目标方法为参照点,根据放置位置的地方不同,通知分为如下5种类型通知:
通知 | 说明 |
---|---|
before(前置通知) | 通知方法在目标方法调用之前执行 |
after(后置通知) | 通知方法在目标方法返回或异常后调用 |
after-returning(返回后通知) | 通知方法会在目标方法返回后调用 |
after-throwing(抛出异常通知) | 通知方法会在目标方法抛出异常后调用 |
around(环绕通知) | 通知方法会将目标方法封装起来 |
AOP的实现
添加 Spring AOP 框架⽀持
创建一个控制类EasyAController
@RestController
public class EasyAController {
//连接点
@RequestMapping("testA")
public String testA(){
System.out.println("testA方法------");
return "EasyA method";
}
}
创建一个切点,并实现通知
@Aspect
@Component
public class AOPObj {
//定义切点
//execution(* cn.xxx.dao..*(..))
@Pointcut("execution(* com.easy.controller.EasyAController.testA(..))")
public void pointCutTestA(){
//切点
}
//通过动态代理来实现的面向切面的思想,以此在不修改源代码的情况下对已有功能进行增强
@Before("pointCutTestA()")
public void before(){
System.out.println("前置通知----------");
}
@After("pointCutTestA()")
public void after(){
System.out.println("后置通知----------");
}
@AfterThrowing("pointCutTestA()")
public void afterThrowing(){
System.out.println("异常后通知----------");
}
@AfterReturning("pointCutTestA()")
public void afterReturning(){
System.out.println("返回后通知----------");
}
}
@Aspect是aop框架中提供的,表示是一个切面。切面类中最先定义的是切点,用@Pointcut注解表示是一个切点,括号里边是切点表达式。后边的是五大类型的通知。分别是用五大类名称进行注解。
切点表达式
AspectJ(Java 语言的一个 AOP 实现) ⽀持三种通配符
* | 匹配任意字符,只匹配⼀个元素(包,类,或⽅法,⽅法参数) |
... | 匹配任意字符,可以匹配多个元素 ,在表示类时,必须和 * 联合使⽤。 |
+ | 表示按照类型匹配指定类的所有类,必须跟在类名后⾯,如 com.cad.Car+ ,表示继承该类的所有⼦类包括本身 |
切点表达式由切点函数组成,execution是最常用的切点函数,语法为:
execution(modifier? ret-type declaring-type?name-pattern(param-pattern) throws-pattern?)
modifier:匹配修饰符,public, private 等,省略时匹配任意修饰符
ret-type:匹配返回类型,使用 * 匹配任意类型
declaring-type:匹配目标类,省略时匹配任意类型
… 匹配包及其子包的所有类
name-pattern:匹配方法名称,使用 * 表示通配符
*匹配任意方法
set* 匹配名称以 set 开头的方法
param-pattern:匹配参数类型和数量
() 匹配没有参数的方法
(…) 匹配有任意数量参数的方法
(*) 匹配有一个任意类型参数的方法(*,String) 匹配有两个参数的方法,并且第一个为任意类型,第二个为 String 类型
throws-pattern:匹配抛出异常类型,省略时匹配任意类型
使用示例
// 匹配public方法
execution(public * *(..))
// 匹配名称以set开头的方法
execution(* set*(..))
// 匹配AccountService接口或类的方法
execution(* com.xyz.service.AccountService.*(..))
// 匹配service包及其子包的类或接口
execution(* com.xyz.service..*(..))