AOP概述
1.什么是AOP?
AOP是一种设计思想,在不修改源代码的情况下给程序动态统一添加额外功能的一种技术,如图:
2.AOP应用原理分析
AOP底层基于代理机制(动态方式)实现功能扩展:
1):假如目标对象(被代理对象)实现接口,则底层可以采用JDK动态代理机制为目标对象创建代理对象(目标类和代理类会实现共同接口)。
2):假如目标对象(被代理对象)没有实现接口,则底层可以采用CGLIB代理机制为目标对象创建代理对象(默认创建的代理类会继承目标对象类型)。
如图:
AOP默认使用CGLIB代理,如需使用JDK代理配置文件配置:
spring.aop.proxy-target-class=false
基于JDK代理方式实现:
基于CGLIB代理方式实现:
AOP相关术语:
切面(aspect):一般为一个具体类(@Aspect注解注释)切入点()
通知(Advice):在切面的某个特定点上执行的扩展
切入点(pointcut):使用@Pointcut注解进行切入点的描述,使用bean表达式定义切入点,语法:bean(spring容器中管理的某个bean的名字),bean表达式是一种粗粒度的切入点表达式(不能具体到bean中哪个方法)需写一个方法作为承载切入点
连接点(joinpoint):封装了切入点集合方法中的某个正在执行的目标方法
AOP添加的依赖:
spring-boot-starter-aop
注解说明:
- @Aspect 注解用于标识或者描述AOP中的切面类型,基于切面类型构建的对象用于为目标对象进行功能扩展或控制目标对象的执行。
- @Pointcut注解用于描述切面中的方法,并定义切面中的切入点(基于特定表达式的方式进行描述),在本案例中切入点表达式用的是bean表达式,这个表达式以bean开头,bean括号中的内容为一个spring管理的某个bean对象的名字。
- @Around注解用于描述切面中方法,这样的方法会被认为是一个环绕通知(核心业务方法执行之前和之后要执行的一个动作),@Aournd注解内部value属性的值为一个切入点表达式或者是切入点表达式的一个引用(这个引用为一个@PointCut注解描述的方法的方法名)。
- ProceedingJoinPoint类为一个连接点类型,此类型的对象用于封装要执行的目标方
通知类型(通知-Advice描述的是一种扩展业务):
1.@Before。(目标方法执行之前执行)
2.@AfterReturning。(目标方法成功结束时执行)
3.@AfterThrowing。(目标方法异常结束时执行)
4.@After。(目标方法结束时执行)
5.@Around.(重点掌握,目标方法执行前后都可以做业务拓展)(优先级最高)
说明:在切面类中使用什么通知,由业务决定,并不是说,在切面中要把所有通知都写上。
切入点表达式增强:
**
bean表达式(重点)
bean表达式一般应用于类级别,实现粗粒度的切入点定义,案例分析:
- bean("userServiceImpl")指定一个userServiceImpl类中所有方法。
- bean("*ServiceImpl")指定所有后缀为ServiceImpl的类中所有方法。
说明:bean表达式内部的对象是由spring容器管理的一个bean对象,表达式内部的名字应该是spring容器中某个bean的name。
缺陷:不能精确到具体方法,也不能针对于具体模块包中的方法做切入点设计
===========================================================
within表达式(了解)
within表达式应用于类级别,实现粗粒度的切入点表达式定义,案例分析:
- within("aop.service.UserServiceImpl")指定当前包中这个类内部的所有方法。
- within("aop.service.*") 指定当前目录下的所有类的所有方法。
- within("aop.service..*") 指定当前目录以及子目录中类的所有方法。
within表达式应用场景分析:
1)对所有业务bean都要进行功能增强,但是bean名字又没有规则。
2)按业务模块(不同包下的业务)对bean对象进行业务功能增强。
===========================================================
execution表达式(了解)
execution表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析:
语法:execution(返回值类型 包名.类名.方法名(参数列表))。
- execution(void aop.service.UserServiceImpl.addUser())匹配addUser方法。
- execution(void aop.service.PersonServiceImpl.addUser(String)) 方法参数必须为String的addUser方法。
- execution( aop.service...*(..)) 万能配置。
===========================================================
@annotation表达式(重点)
@annotaion表达式应用于方法级别,实现细粒度的切入点表达式定义,案例分析
- @annotation(anno.RequiredLog) 匹配有此注解描述的方法。
- @annotation(anno.RequiredCache) 匹配有此注解描述的方法。
其中:RequiredLog为我们自己定义的注解,当我们使用@RequiredLog注解修饰业务层方法时,系统底层会在执行此方法时进行日扩展操作。
切面优先级设置实现
切面的优先级需要借助@Order注解进行描述,数字越小优先级越高,默认优先级比较低。
列如:@Order(1),@Order(2)