1. AOP解释
在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。
2. AOP的基本概念和用到的注解
2.1Aspect
(切面):
通常是指通用功能封装成的这个类,里面可以定义切点和通知。
切面类一般加@Aspect
和@Compent
注解
2.2 Pointcut
(切点):
指定要插入该切面(类)的地方,用表达式来定义。一个切面中可以定义多个Pointcut。
@Pointcut
注解包括表达式和签名(一个空方法)。表达式有以下10种类型的:
//Pointcut表示式
@Pointcut("execution(* com.test.demo.*(..))")
//Point签名
private void log(){}
-
- execution:一般用于指定方法的执行,用的最多
- 匹配所有方法
execution(* *(..))
- 匹配所有公共方法
execution(public * *(..))
- 匹配所有add()方法
execution(* add())
- 匹配所有抛出Exception的方法
execution(* *(..) throws Exception)
- 匹配类或者接口中的方法
execution(* com.test.ServiceImpl.*(..))
- 匹配指定包(不包含子包)下所有类中的所有方法
execution(* com.test.*.*(..))
- 匹配指定包及其子包下的所有类中以add开头的所有public方法
execution(public * com.test..*.add*(..))
-
- within 指定某些类的全部方法执行,也可用来指定一个包。
- 匹配service包(不包含子包)中任意类的方法
within(com.test.service.*)
- 匹配service包及子包中任意类的方法
within(com.test.service..*)
-
- this
Spring Aop是基于代理的,this就表示代理对象。this类型的Pointcut表达式的语法是this(type),当生成的代理对象可以转换为type指定的类型时则表示匹配。基于JDK接口的代理和基于CGLIB的代理生成的代理对象是不一样的。
- 匹配生成的代理对象是IUserService类型的所有方法的外部调用
this(com.test.UserService)
- this
-
- target
Spring Aop是基于代理的,target则表示被代理的目标对象。当被代理的目标对象可以被转换为指定的类型时则表示匹配。
- 匹配被代理的目标对象能够转换为UserService类型的所有方法的外部调用
target(com.elim.spring.aop.service.UserService)
this 和 target 的不同点:
-- this作用于代理对象,target作用于目标对象
-- this表示目标对象被代理之后生成的代理对象和指定的类型匹配会被拦截,匹配的是代理对象
-- target表示目标对象和指定的类型匹配会被拦截,匹配的是目标对象
- target
-
- args 用来匹配方法参数的。
- 匹配任何不带参数的方法
args()
- 匹配任何只带一个String类型参数的方法
args(java.lang.String)
- 匹配带任意参数的方法
args(..)
- 匹配带任意个参数,但是第一个参数的类型是String的方法
args(java.lang.String,..)
- 匹配带任意个参数,但是最后一个参数的类型是String的方法
args(..,java.lang.String)
-
- @target 匹配当被代理的目标对象对应的类型及其父类型上拥有指定的注解时。
- 目标对象中包含指定注解
@target(com.elim.spring.support.MyAnnotation)
-
- @args 方法参数所属的类型上有指定的注解
- 匹配方法参数类型上拥有MyAnnotation注解的方法调用。如我们有一个方法add(MyParam param)接收一个MyParam类型的参数,而MyParam这个类是拥有注解MyAnnotation
@args(com.elim.spring.support.MyAnnotation)
-
- @within用于匹配被代理的目标对象对应的类型或其父类型拥有指定的注解的情况,但只有在调用拥有指定注解的类上的方法时才匹配。
- 匹配被调用的方法声明的类上拥有RestController注解
@within(org.springframework.web.bind.annotation.RestController)
比如有一个ClassA上使用了注解MyAnnotation标注,并且定义了一个方法a(),那么在调用ClassA.a()方法时将匹配该Pointcut;如果有一个ClassB上没有MyAnnotation注解,但是它继承自ClassA,同时它上面定义了一个方法b(),那么在调用ClassB().b()方法时不会匹配该Pointcut。但是在调用ClassB().a()时将匹配该方法调用,因为a()是定义在父类型ClassA上的,且ClassA上使用了MyAnnotation注解。但是如果子类ClassB覆写了父类ClassA的a()方法,则调用ClassB.a()方法时也不匹配该Pointcut。
-
- @annotation用于匹配方法上拥有指定注解的情况。
- 匹配所有拥有MyAnnotation注解的方法
@annotation(io.swagger.annotations.ApiOperation)
-
- bean 这是Spring增加的一种方法,spring独有。用于匹配当调用的是指定的Spring的某个bean的方法时
-
bean(abc)
匹配Spring Bean容器中id或name为abc的bean的方法调用 -
bean(user*)
匹配所有id或name为以user开头的bean的方法调用
Pointcut定义时,还可以使用&&、||、! 这三个运算
-
bean(userService) && args()
匹配id或name为userService的bean的所有无参方法。 -
bean(userService) || @annotation(MyAnnotation)
匹配id或name为userService的bean的方法调用,或者是方法上使用了MyAnnotation注解的方法调用。 -
bean(userService) && !args()
匹配id或name为userService的bean的所有有参方法调用。
2.3 Advice
(通知):
用来定义切点要实现的业务逻辑。一般是方法,方法中 写 逻辑。
Advice
的类型
-
before advice
, 在 join point 前被执行的 advice. 虽然 before advice 是在 join point 前被执行, 但是它并不能够阻止 join point 的执行, 除非发生了异常(即我们在 before advice 代码中, 不能人为地决定是否继续执行 join point 中的代码) -
after return advice
, 在一个 join point 正常返回后执行的 advice -
after throwing advice
, 当一个 join point 抛出异常后执行的 advice -
after(final) advice
, 无论一个 join point 是正常退出还是发生了异常, 都会被执行的 advice. -
around advice
, 在 join point 前和 joint point 退出后都执行的 advice. 这个是最常用的 advice. -
introduction
,introduction可以为原有的对象增加新的属性和方法。
2.4 JointPoint
(连接点、插入点):
表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等
SpringBoot加入AOP的例子见文章 ====>>>> Springboot添加AOP打印请求参数
网友评论