Spring之AOP

什么是AOP?

        面向切面编程,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取公共模块复用,降低偶合。

Spring中事务是如何实现的?

        其本质是通过AOP功能,对方法前后进行拦截,在执行方法开始之前开启事务,在执行完成目标方法之后根据执行情况提交或者回滚事务。

1、什么是AOP

AOP称为面向切面编程,用于将那些与业务无关,却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为“切面”(Aspect),减少系统中重复代码,降低模块间的耦合度,同时提高系统的可维护性。

  1. 切点(Pointcut):定义了切面要作用的目标对象或方法。切点可以通过表达式、注解方式或者方法名匹配的方式进行定义。
  2. 通知(Advice):定义在切点何时执行的逻辑。通知可以在切点之前、之后或者异常抛出时进行执行。
  3. 切面(Aspect):由切点和通知组成的编程模块,用于定义特定的关注点。
  4. 织入(Weaving):将切面和目标对象进行关联的过程。织入可以在编译时、类加载时或者运行时进行。
  5. 连接点(Joinpoint):目标对象中能够被切面拦截的方法。连接点可以被通知所影响。
  6. 引入(Introduction):将新的接口或方法引入到目标对象中的过程。引入可以使得目标对象具有新的能力。
  7. 切面优先级(Aspect Ordering):定义多个切面之间的执行顺序。优先级高的切面可以被优先执行。

2、常见的AOP使用场景:

  • 记录操作日志
  • 缓存处理
  • Spring中内置的事务处理

3、AOP使用场景-记录操作日志

3.1、记录操作日志的思路

        其核心是:使用AOP中的环绕通知+切点表达式(找到要记录日志的方法),通过环绕通知的参数获取请求方法的参数(类、方法、注解、请求方式等),获取到这些参数以后,保存到数据库。

3.2、记录操作日志的实现

 (基于Spring Boot)

1.添加AOP依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.创建一个切面类并使用@Aspect注解标记它

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
 
@Aspect
@Component
public class LogAspect {
 
    @Pointcut("execution(* com.yourpackage..*.*(..))") // 根据实际情况配置切点表达式
    public void logPointcut() {
    }
 
    @Before("logPointcut()")
    public void doBefore(JoinPoint joinPoint) {
        // 在此处记录请求开始的日志,例如请求方法、参数等
    }
 
    @AfterReturning(pointcut = "logPointcut()", returning = "retVal")
    public void doAfterReturning(Object retVal) {
        // 在此处记录请求结束的日志,例如响应结果等
    }
}

3.配置AOP,确保切面类被Spring容器管理。

4.在控制器或服务层的方法上使用注解(如@RequestMapping, @Service等),AOP将自动应用日志记录逻辑。

4、AOP使用场景-Spring事务的实现

Spring支持编程式事务管理和声明式事务管理两种方式。

编程式事务控制:需使用Transction Template来实现,对业务代码有侵入性,一般很少使用。

声明式事务管理:声明式事务管理建立在AOP之上的。其本质是通过AOP功能,对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行目标方法之后根据执行情况提交或回滚事务。

4.1.Spring事务使用示例(重要)

 1.使用@Transactional注解

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
@Service
public class SomeService {
 
    @Transactional
    public void someMethod() {
        // do some database operations
    }
}

在上述代码中,someMethod()方法被@Transactional注解包围,这意味着Spring将此方法的调用包装在一个事务中。如果方法成功完成,Spring将提交事务。如果方法抛出异常,Spring将回滚事务。

4.2.Spring事务使用示例(拓展)

2.使用XML配置

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
 
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
 
    <tx:annotation-driven transaction-manager="transactionManager" />
 
</beans>

在上述配置中,定义了一个事务管理器,并通过tx:annotation-driven告诉Spring我们想要基于注解的事务管理。然后我们可以在服务类的方法上使用@Transactional注解来声明事务。

3.使用Java配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
 
import javax.sql.DataSource;
 
@Configuration
@EnableTransactionManagement
public class AppConfig {
 
    @Bean
    public DataSourceTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}

在上述Java配置中,我们使用@EnableTransactionManagement注解启用注解事务管理。然后我们定义了一个事务管理器的bean,可以在服务类的方法上使用@Transactional注解来声明事务。

5、使用Spring事务的注意事项

在使用Spring事务时,需确保数据源是支持事务的。例如,

  • 如果使用的是JDBC,那么数据源必须是实现了PlatformTransactionManager接口的类的实例,如DataSourceTransactionManager。
  • 如果你使用的是MyBatis,那么需要使用Spring的SqlSessionFactoryBean来创建SqlSessionFactory,并且使用Spring的事务管理器DataSourceTransactionManager。

特别地,在需要使用Spring事务时,我们需要保证Srping事务是生效的。这也是一个老生常谈的话题了:链接:Spring之事务失效的场景

上一篇:【Linux 基础】df -h 的输出信息解读


下一篇:从头开始学习扩散模型 Stable Diffusion