1. 什么是Spring AOP?
AOP (Aspect Orient Programming),直译过来就是 面向切面编程,AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向切面编程,实现在不修改源代码的情况下给程序动态统一添加额外功能的一种技术。AOP可以拦截指定的方法并且对方法增强,而且无需侵入到业务代码中,使业务与非业务处理逻辑分离,比如Spring的事务,通过事务的注解配置,Spring会自动在业务方法中开启、提交业务,并且在业务处理失败时,执行相应的回滚策略。
在Spring AOP中,可以将横切关注点定义为一个切面(Aspect),并将其与特定的连接点(Join Point)相连接。连接点是程序的一个执行点,例如方法调用或异常抛出。切面可以在连接点周围执行通知(Advice),在它们被调用时添加额外的行为。
2.AOP的作用
AOP 采取横向抽取机制(动态代理),取代了传统纵向继承机制的重复性代码,其应用主要体现在事务处理、日志管理、权限控制、异常处理等方面。
主要作用是分离功能性需求和非功能性需求,使开发人员可以集中处理某一个关注点或者横切逻辑,减少对业务代码的侵入,增强代码的可读性和可维护性。
简单的说,AOP 的作用就是保证开发者在不修改源代码的前提下,为系统中的业务组件添加某种通用功能。
3.AOP组成
(1)切面 (Aspect)
切面(Aspect)由切点(Pointcut)和通知(Advice)组成,它既包含了横切逻辑的定义,也包括了连接点的定义。
切⾯是包含了:通知、切点和切⾯的类,相当于 AOP 实现的某个功能的集合。
(2)连接点 (Join Point)
应⽤执⾏过程中能够插⼊切⾯的⼀个点,这个点可以是⽅法调⽤时,抛出异常时,甚⾄修改字段时。切⾯代码可以利⽤这些点插⼊到应⽤的正常流程之中,并添加新的⾏为。
连接点相当于需要被增强的某个 AOP 功能的所有⽅法。
(3) 切点 (Pointcut)
Pointcut 是匹配 Join Point 的谓词。
Pointcut 的作⽤就是提供⼀组规则(使⽤ AspectJ pointcut expression language 来描述)来匹配 Join Point,给满⾜规则的 Join Point 添加 Advice。
切点相当于保存了众多连接点的⼀个集合(如果把切点看成⼀个表,⽽连接点就是表中⼀条⼀条的数据)。
(4) 通知 / 增强方法 (Advice)
切⾯也是有⽬标的 ——它必须完成的⼯作。在 AOP 术语中,切面的工作被称之为通知。
通知:定义了切⾯是什么,何时使⽤,其描述了切⾯要完成的⼯作,还解决何时执⾏这个⼯作的问题。
Spring 切⾯类中,可以在⽅法上使⽤以下注解,会设置⽅法为通知⽅法,在满⾜条件后会通知本⽅法进⾏调⽤:
前置通知使⽤ @Before:通知⽅法会在⽬标⽅法调⽤之前执⾏。 后置通知使⽤ @After:通知⽅法会在⽬标⽅法返回或者抛出异常后调⽤。 返回之后通知使⽤ @AfterReturning:通知⽅法会在⽬标⽅法返回后调⽤。 抛异常后通知使⽤ @AfterThrowing:通知⽅法会在⽬标⽅法抛出异常后调⽤。 环绕通知使⽤ @Around:通知包裹了被通知的⽅法,在被通知的⽅法通知之前和调⽤之后执⾏⾃定义的⾏为。
4. Spring事务管理
Spring框架提供了一套强大的事务管理 API,使得开发者能够更容易地完成事务的管理。Spring事务管理有以下几种事务模型:
-
编程式事务管理:这种事务管理方式需要在代码中显式地编写事务代码。使用
TransactionTemplate
类或基于注解的事务模式可以实现编程式事务管理。 -
声明式事务管理:这种事务管理方式通过配置文件或注解来声明哪些方法需要进行事务管理。使用Spring AOP来完成方法切面,从而统一管理事务。
Spring框架还支持以下几种声明式事务管理的传播机制:
-
REQUIRED:如果当前存在一个事务,则加入该事务;否则创建一个新事务。
-
SUPPORTS:如果当前存在事务,则加入该事务;否则以非事务方式运行。
-
MANDATORY:如果当前存在一个事务,则加入该事务;否则抛出异常。
-
REQUIRES_NEW:创建一个新事务,并暂停当前事务(如果存在)。
-
NOT_SUPPORTED:以非事务方式运行,并挂起当前事务(如果存在)。
-
NEVER:以非事务方式运行;如果当前存在一个事务,则抛出异常。
-
NESTED:如果当前存在事务,则在嵌套事务内执行;否则按照 REQUIRED 执行。
5.Spring AOP和事务的整合
通过Spring AOP,我们可以将事务管理切面声明为一个切面,并将其与业务逻辑方法相连接。然后,我们可以使用声明式事务管理来定义我们的事务处理,从而实现对所有业务逻辑方法的统一事务管理。
以下是使用Spring AOP和事务的代码示例:
@Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Transactional @Override public void saveUser(User user) { userDao.saveUser(user); } @Transactional @Override public User getUserById(Integer id) { return userDao.getUserById(id); } }
在上面的示例中,可以看到@Transactional
注解被用于业务逻辑方法中。Spring AOP会将这些方法处理为切点,连接到事务管理切面上。这样,所有的业务逻辑方法都都会受到事务管理的影响,当方法被调用时,会在事务的范围内进行操作。
在以上示例中,@Transactional
注解应用于saveUser()
和getUserById()
方法。这意味着这两个方法在被调用时会处于一个事务的上下文中。如果方法执行成功,事务会被提交;如果方法抛出异常,事务会被回滚。
此外,需要注意的是,事务管理切面的声明通常应该在Spring配置文件中进行。您可以使用<tx:annotation-driven>
来启用基于注解的事务管理。这样,Spring会自动扫描带有@Transactional
注解的方法,并为它们创建事务代理。
6. 总结
通过学习Spring AOP和事务相关知识,我们可以实现更好的模块化和可维护性。Spring AOP允许我们将横切关注点与业务逻辑分离,并以声明式的方式进行管理。事务管理提供了对数据库操作的原子性和一致性的支持。
在使用Spring AOP和事务管理时,需要注意以下几点:
-
在业务逻辑方法中使用
@Transactional
注解即可启用事务管理。 -
根据需要选择合适的事务传播机制。
-
在Spring配置文件中声明事务管理切面,并启用基于注解的事务管理。