AOP(Aspect-Oriented Programming,面向切面编程)是一种编程技术,它允许开发者在不改变现有代码的情况下,增加新的功能或行为,这些功能或行为被称为“切面”。
AOP 可以通过预编译方式和运行期动态代理的方式来实现,它的主要目的是降低业务逻辑的耦合性,提高程序的可重用性和开发效率。
AOP 常用于统一功能的处理,例如:事务管理、日志记录、权限检查等功能。
1.AOP优点分析
使用 AOP 的主要原因有以下几点:
- 模块化:通过将公共行为(如日志记录、事务管理)提取为独立的切面,可以使代码更加模块化,提高代码的可维护性和可读性。
- 减少重复代码:通过使用 AOP,可以将重复的代码(如日志记录、权限检查)提取到一个切面中,避免在多个地方重复编写相同的代码。
解耦:AOP 允许开发者将业务逻辑与横切关注点(如日志记录、事务管理)分离,从而降低业务逻辑的耦合性,提高程序的可重用性和可扩展性。
2.AOP技术实现
AOP 实现技术主要分为两大类:静态代理和动态代理。
静态代理:通过 AOP 框架提供的命令进行编译,从而在编译阶段生成 AOP 代理类。这种方式也被称为编译时增强。静态代理包括编译时编织和类加载时编织两种方式。
- 动态代理:在运行时在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。动态代理主要有两种实现方式:
- JDK 动态代理:JDK 动态代理要求被代理的类必须实现一个接口,它通过反射来接收被代理的类,并使用 InvocationHandler 接口和 Proxy 类实现代理。
- CGLIB 动态代理:CGLIB 则是一个代码生成的类库,它可以在运行时动态地生成某个类的子类,通过继承的方式实现代理。如果目标类没有实现接口,Spring AOP 会选择使用 CGLIB 来动态代理目标类。
3.AOP实现原理
Spring AOP(面向切面编程)的实现原理主要基于动态代理技术,它提供了对业务逻辑各个方面的关注点分离和模块化,使得非功能性需求(如日志记录、事务管理、安全检查等)可以集中管理和维护,而不是分散在各个业务模块中。
Spring AOP 实现原理的关键要点如下:
- 代理机制:
- JDK 动态代理:对于实现了接口的目标类,Spring AOP 默认使用 JDK 的 java.lang.reflect.Proxy 类来创建代理对象。代理对象会在运行时实现代理接口,并覆盖其中的方法,在方法调用前后执行切面逻辑(即通知,advice)。
- CGLIB 动态代理:对于未实现接口的类,Spring AOP 会选择使用 CGLIB 库来生成代理对象。CGLIB 通过字节码技术创建目标类的子类,在子类中重写目标方法并在方法调用前后插入切面逻辑。
- 关键概念:
- 切面(Aspect):切面是一个包含了横切关注点声明的模块化单元,它可以有多个切入点和通知组成。
- 切入点(Pointcut):切入点定义了匹配通知应该被织入的方法或方法执行点的规则表达式。
- 通知(Advice):通知是在特定切入点处执行的代码片段,分为多种类型,如前置通知(Before advice)、后置通知(After returning advice)、异常后通知(After throwing advice)、最终通知(After (finally) advice)以及环绕通知(Around advice)。
- 织入(Weaving):织入是指将切面应用到目标对象来创建一个新的代理对象的过程。在 Spring AOP 中,织入发生在运行时,通过代理对象的方式实现。
- 代理工厂:Spring 内部通过 ProxyFactory 或相关的 AOP 基础设施(如 Advisor、AdvisorChainFactory 等)来创建和管理代理对象。
- 执行流程:当客户端通过代理对象调用目标方法时,代理对象会拦截这个调用,根据切面配置找到对应的通知,并按照通知类型的不同执行相应的增强逻辑。例如,如果是环绕通知,它会完全控制原始方法的调用过程,可以在调用前后插入自定义逻辑,甚至决定是否执行原方法。
通过上述方式,Spring AOP 巧妙地实现了对目标对象方法的拦截和增强,从而实现了面向切面编程的功能。
课后思考
Spring 动态代理失效的场景有哪些?Spring Boot 动态代理默认实现是 JDK 动态代理还是 CGLIB?怎么证明?
本文已收录到我的面试小站 www.javacn.site,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。