SpringAOP
SpirngAOP
谈谈自己对于 AOP 的了解?
AOP(Aspect-Oriented Programming:面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。所谓切面,相当于应用对象间的横切点,我们可以将其单独抽象为单独的模块。
Spring AOP 就是基于动态代理的,如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会使用 Cglib 生成一个被代理对象的子类来作为代理,如下图所示:

当然你也可以使用 AspectJ ,Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。
AOP 切面编程涉及到的一些专业术语:
术语 | 含义 |
---|---|
目标(Target) | 被通知的对象 |
代理(Proxy) | 向目标对象应用通知之后创建的代理对象 |
连接点(JoinPoint) | 目标对象的所属类中,定义的所有方法均为连接点 |
切入点(Pointcut) | 被切面拦截 / 增强的连接点(切入点一定是连接点,连接点不一定是切入点) |
通知(Advice) | 增强的逻辑 / 代码,也即拦截到目标对象的连接点之后要做的事情 |
切面(Aspect) | 切入点(Pointcut)+通知(Advice) |
Weaving(织入) | 将通知应用到目标对象,进而生成代理对象的过程动作,分为编译器织入和运行时织入 |
JDK Proxy 和 Cglib的区别
JDK Proxy: JDK Proxy是基于Java的反射机制实现的。它要求被代理的类实现一个或多个接口,然后通过java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口来创建代理对象和处理代理方法调用。JDK Proxy适用于代理接口的情况。它要求被代理的类实现接口,然后基于接口生成代理对象。由于Java只支持单继承,因此JDK Proxy无法直接代理没有实现接口的类。
Cglib:Cglib是通过继承被代理类并生成子类来实现的。它通过字节码操作库(ASM或Byte Buddy)在运行时动态生成被代理类的子类(运行时直接在内存中生成并加载修改后的字节码文件),并重写需要代理的方法。Cglib适用于代理类的情况。它可以直接代理没有实现接口的类,通过生成被代理类的子类来实现代理。
AOP 解决了什么问题?
OOP 不能很好地处理一些分散在多个类或对象中的公共行为(如日志记录、事务管理、权限控制、接口限流、接口幂等等),这些行为通常被称为 横切关注点(cross-cutting concerns) 。如果我们在每个类或对象中都重复实现这些行为,那么会导致代码的冗余、复杂和难以维护。
AOP 可以将横切关注点(如日志记录、事务管理、权限控制、接口限流、接口幂等等)从 核心业务逻辑(core concerns,核心关注点) 中分离出来,实现关注点的分离。

具体实现
1 |
|
Spring AOP 和 AspectJ AOP 有什么区别?
Spring AOP 属于运行时增强,而 AspectJ 是编译时增强。 Spring AOP 基于代理(Proxying),而 AspectJ 基于字节码操作(Bytecode Manipulation)。
Spring AOP 已经集成了 AspectJ ,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。AspectJ 相比于 Spring AOP 功能更加强大,但是 Spring AOP 相对来说更简单,
如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择 AspectJ ,它比 Spring AOP 快很多。
AspectJ 定义的通知类型有哪些?
- Before(前置通知):目标对象的方法调用之前触发
- After (后置通知):目标对象的方法调用之后触发
- AfterReturning(返回通知):目标对象的方法调用完成,在返回结果值之后触发
- AfterThrowing(异常通知):目标对象的方法运行中抛出 / 触发异常后触发。AfterReturning 和 AfterThrowing 两者互斥。如果方法调用成功无异常,则会有返回值;如果方法抛出了异常,则不会有返回值。
- Around (环绕通知):编程式控制目标对象的方法调用。环绕通知是所有通知类型中可操作范围最大的一种,因为它可以直接拿到目标对象,以及要执行的方法,所以环绕通知可以任意的在目标对象的方法调用前后搞事,甚至不调用目标对象的方法
如何实现环绕通知?
在Spring AOP中,环绕通知(Around Advice)是一种比较灵活的通知类型,它可以在目标方法执行前后执行额外的逻辑,并且还可以决定是否调用目标方法。
在Spring AOP中,环绕通知(Around Advice)是一种比较灵活的通知类型,它可以在目标方法执行前后执行额外的逻辑,并且还可以决定是否调用目标方法。下面是使用环绕通知的步骤:
- 定义环绕通知方法:首先,需要在切面类中定义一个方法,该方法使用
@Around
注解标记,以表示它是一个环绕通知。方法的签名必须是public Object
类型,并且接受一个ProceedingJoinPoint
类型的参数。在方法内部可以编写环绕通知的逻辑,并通过ProceedingJoinPoint
对象来控制目标方法的执行。 - 编写环绕通知逻辑:在环绕通知方法内部,可以编写额外的逻辑,例如日志记录、性能监控、事务管理等。可以在目标方法执行前执行预处理逻辑,在目标方法执行后执行后续处理逻辑,并且可以决定是否调用
ProceedingJoinPoint
对象的proceed()
方法来执行目标方法。 - 指定切入点表达式:在
@Around
注解中指定切入点表达式,以确定环绕通知应该织入到哪些目标方法中。
1 |
|
多个切面的执行顺序如何控制?
1、通常使用@Order
注解直接定义切面顺序
1 |
|
2、实现Ordered
接口重写 getOrder
方法。
1 |
|