问题思考
我们为啥要使用AOP?
来看一个案例:
声明计算器接口Calculator,包含加减乘除的抽象方法
public interface Calculator {int add(int i, int j);int sub(int i, int j);int mul(int i, int j);int div(int i, int j);
}
public class CalculatorPureImpl implements Calculator {@Overridepublic int add(int i, int j) {int result = i + j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int sub(int i, int j) {int result = i - j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int mul(int i, int j) {int result = i * j;System.out.println("方法内部 result = " + result);return result;}@Overridepublic int div(int i, int j) {int result = i / j;System.out.println("方法内部 result = " + result);return result;}
}
创建带日志功能的实现类
public class CalculatorLogImpl implements Calculator {@Overridepublic int add(int i, int j) {System.out.println("[日志] add 方法开始了,参数是:" + i + "," + j);int result = i + j;System.out.println("方法内部 result = " + result);System.out.println("[日志] add 方法结束了,结果是:" + result);return result;}@Overridepublic int sub(int i, int j) {System.out.println("[日志] sub 方法开始了,参数是:" + i + "," + j);int result = i - j;System.out.println("方法内部 result = " + result);System.out.println("[日志] sub 方法结束了,结果是:" + result);return result;}@Overridepublic int mul(int i, int j) {System.out.println("[日志] mul 方法开始了,参数是:" + i + "," + j);int result = i * j;System.out.println("方法内部 result = " + result);System.out.println("[日志] mul 方法结束了,结果是:" + result);return result;}@Overridepublic int div(int i, int j) {System.out.println("[日志] div 方法开始了,参数是:" + i + "," + j);int result = i / j;System.out.println("方法内部 result = " + result);System.out.println("[日志] div 方法结束了,结果是:" + result);return result;}
}
这个时候我们发现代码缺陷:
- 对核心业务功能有干扰,导致程序员在开发核心业务功能时分散了精力
- 附加功能分散在各个业务功能方法中,不利于统一维护
解决这两个问题,核心就是:解耦。我们需要把附加功能从业务功能代码中抽取出来。
解决问题的困难:要抽取的代码在方法内部,靠以前把子类中的重复代码抽取到父类的方式没法解决。所以需要引入新的技术。
这其实就是我们的AOP思想 - 解耦。
AOP概述
Spring AOP(Aspect-Oriented Programming)是Spring框架提供的一种面向切面编程的支持。它允许开发者通过定义切面(Aspect)来将横切关注点(Cross-cutting Concerns)与核心业务逻辑分离,从而提高代码的可维护性和可重用性。
在Spring AOP中,切面是一个模块化的单元,它横跨多个类和对象,用于封装横切关注点。横切关注点是那些在应用程序中散布在各处的功能,如日志记录、事务管理、安全性等,它们与核心业务逻辑无关,但又需要在多个地方重复使用。
Spring AOP通过使用代理模式和动态代理技术,在运行时动态地将切面织入到目标对象的方法中,从而实现横切关注点的功能。开发者可以使用注解或XML配置来定义切面和切点,以及指定切面的行为和执行时机。
Spring AOP的核心概念包括:
-
Aspect(切面):封装了横切关注点的模块。一个切面是由多个join points和相关的advice组成。
-
Join Point(连接点):在程序执行过程中的某个点,如方法调用或异常抛出,可以被AOP织入的地方。
-
Advice(通知):在特定的join point执行的代码,如before、after、around等类型的通知。
-
Pointcut(切入点):一个或多个join points的集合,通过表达式语言来定义哪些join points会被编织上advice。
-
Weaving(织入):将aspect和advice插入到程序的join points的过程,Spring AOP在运行时通过代理实现这一点。
-
Target Object(目标对象):被通知的对象,即被AOP增强的真实对象。
-
Proxy(代理):包含目标对象以及附加的AOP行为的对象。
Spring AOP主要通过两种代理机制实现AOP:
-
JDK动态代理:用于实现接口的代理,利用Java反射机制创建代理对象。
-
CGLIB(Code Generation Library):用于实现类的代理,通过字节码生成库来创建子类对象。
通过使用Spring AOP,开发者可以更容易地维护和扩展应用,因为那些与业务逻辑无关的代码可以被集中管理和修改,而不必改动核心的业务逻辑代码。这有助于降低系统复杂度,提高代码的可读性和可维护性。
为啥Spring 要使用AOP?
Spring框架选择使用AOP(Aspect Oriented Programming,面向切面编程)的主要原因在于解决传统面向对象编程(OOP)中遇到的一些挑战,特别是在处理横切关注点(cross-cutting concerns)方面。下面列出了一些关键的原因:
-
解耦合:在OOP中,横切关注点(如日志记录、缓存、权限检查、事务管理等)常常需要在多个地方重复编码,这导致代码耦合度高,难以维护和扩展。AOP允许将这些关注点从核心业务逻辑中分离出来,降低系统的耦合度。
-
代码重用和模块化:通过AOP,你可以编写一次横切关注点的代码,并在多个不同的地方使用它,无需在每个受影响的模块中重复相同的代码。这提高了代码的重用性和模块化。
-
简化开发和维护:AOP使得开发人员可以专注于业务逻辑的实现,而将通用的服务(如日志、事务管理)留给AOP切面处理。这不仅简化了开发流程,也便于后期维护,因为所有的日志或事务相关代码都集中在一个地方。
-
透明性:使用AOP,可以向现有代码添加新的功能,而无需修改原有代码。例如,如果需要在所有数据库操作前后添加日志记录,可以通过AOP轻松实现,而不需要修改每个涉及数据库操作的方法。
-
灵活的配置:Spring AOP允许通过XML配置文件或者注解来定义切点(pointcuts)、通知(advice)和切面(aspects),这提供了非常灵活的配置选项,使得开发者可以根据需要轻松调整AOP的行为。
-
事务管理:Spring AOP特别擅长处理事务管理。通过声明式事务管理,开发者只需在配置文件或注解中指定事务边界,而不需要在代码中显式地管理事务的开始和结束。
-
性能优势:虽然AOP引入了额外的运行时开销,但由于它减少了代码的重复和耦合,总体上可以带来更好的性能,尤其是在大型企业级应用中。