发布时间:2023-04-24 08:30
AOP(Aspect-Oriented Programming),一般称为面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。
可用于权限认证、日志、事务处理等。
AOP、OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想。
**OOP(面向对象编程)**针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。 AOP作为面向对象的一种补充,则是针对业务处理过程中的切面进行提取, 已达到业务代码和公共行为代码之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。
(1)切面(Aspect): 在Spring Aop指定就是“切面类” ,切面类会管理着切点、通知。
(2)连接点(Join point): 指定就是被增强的业务方法
(3)通知(Advice): 就是需要增加到业务方法中的公共代码, 通知有很多种类型分别可以在需要增加的业务方法
不同位置进行执行(前置通知、后置通知、异常通知、返回通知、环绕通知)
(4)切点(Pointcut): 由他决定哪些方法需要增强、哪些不需要增强, 切点表达式是一个具体的实现
(5)目标对象(Target Object): 指定是增强的对象
(6)织入(Weaving) : spring aop用的织入方式:动态代理。 就是为目标对象创建动态代理的过程就叫织入。(将通知切入连接点的过程)
在AOP术语中,在的某个特定的连接点上执行的动作——官方
Spring切面可以应用5种类型的通知:
当在Spring中要使用@Aspect、@Before.等这些注解的时候, 就需要添加AspectJ相关依赖
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.5version>
dependency>
Spring Aop提供了 AspectJ 的支持,但只用到的AspectJ的切点解析和匹配,@Aspect、@Before.等这些注解
都是由AspectJ 发明的。
AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以
Spring AOP为代表。
Spring AOP使用的动态代理,它基于动态代理来实现。默认地,如果使用接口的,用 JDK 提供的动态代理实现,
如果没有接口,使用 CGLIB 实现。
AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增
强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
属于静态织入,它是通过修改代码来实现的,它的织入时机可以是:
AspectJ 出身也是名门,来自于 Eclipse 基金会
AspectJ 能干很多 Spring AOP 干不了的事情,它是 AOP 编程的完全解决方案。Spring AOP 致力于解决的是企业级开发中最普遍的 AOP 需求(方法织入),而不是力求成为一个像 AspectJ 一样的 AOP 编程完全解决方案。
因为 AspectJ 在实际代码运行前完成了织入,所以大家会说它生成的类是没有额外运行时开销的。很多人会对比 Spring AOP 和 AspectJ 的性能,Spring AOP 是基于代理实现的,在容器启动的时候需要生成代理实例,在方法调用上也会增加栈的深度,使得 Spring AOP 的性能不如 AspectJ 那么好。
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理:
JDK动态代理只提供接口的代理,不支持类的代理
如果代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类
注意:
很多人会对比 JDK和Cglib的性能,jdk动态代理生成类速度快,调用慢,cglib生成类速度慢,但后续调用
快,在老版本CGLIB的速度是JDK速度的10倍左右, 但是实际上JDK的速度在版本升级的时候每次都提高很多性能,而
CGLIB仍止步不前.
@EnableAspectJAutoProxy
(proxyTargetClass = true) //强制CGLIB
(exposeProxy = true) //在线程中暴露代理对象
获取当前线程的动态代理对象,防止调用本类的方法,不会进行增强(cglib本身就实现了,这个主要用于JDK)
public int mod(int numA,int numB){
System.out.println(\"执行目标方法:mod\");
//获取当前线程的动态代理对象,防止调用本类的方法,不会进行增强(cglib本身就实现了,这个主要用于JDK)
int retVal=((Caculate)AopContext.currentProxy()).add(numA,numB);
int retVal=this.add(numA,numB);
return retVal%numA;
}
基于接口的配置
写一个类实现前置通知的接口
接口的方式,需要自己手动创建顾问,配置通知和切入点
基于注解和XML的配置
参考https://blog.csdn.net/shaohe18362202126/article/details/81952082?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165527248816781818740462%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165527248816781818740462&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-1-81952082-null-null.nonecase&utm_term=AOP%E6%9C%89%E5%87%A0%E7%A7%8D%E5%AE%9E%E7%8E%B0%E6%96%B9%E5%BC%8F&spm=1018.2226.3001.4450