springBoot对于事务和AOP的优化

目录

一.概述

二.问题

三.优化

四.结尾


一.概述

        我将提出用spring写事务和aop的程序的问题,然后写springBoot对于它们的优化,以及提出上一篇未曾提起的springboot的核心。

二.问题

        首先,先提出问题:spring对于aop和事务的配置繁琐,需要导入打量jar包,编写配置文件。

我们导入jar包。

<!-- Spring核心依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.20</version> <!-- 版本可根据实际需求调整 -->
</dependency>

<!-- AOP依赖(Spring AOP + AspectJ支持) -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>5.3.20</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.7</version> <!-- AspectJ织入器,用于解析切面表达式 -->
</dependency>

<!-- 事务管理依赖(如果使用JDBC/MyBatis等,需额外引入对应数据源依赖) -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>5.3.20</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId> <!-- 提供DataSourceTransactionManager -->
    <version>5.3.20</version>
</dependency>

因为先设置aop,才能配置事务,我们先来看aop的配置。

AOP配置的顺序。

1.先开启aop的自动代理

2.定义切面类和切入点

3.定义通知

前提,要确保它们全部都已经注册进入容器。

第一步:

注解方式:

@Configuration
@ComponentScan("com.pxq") // 扫描组件(包括切面类)
@EnableAspectJAutoProxy // 开启AOP自动代理
public class SpringConfig {
}

xml方式:

<!-- 扫描组件(可选,若切面类用@Component标记) -->
<context:component-scan base-package="com.pxq"/>

<!-- 开启AOP自动代理 -->
<aop:aspectj-autoproxy/>

第二三步:

注解方式:

@Component // 纳入Spring容器管理
@Aspect // 标记为切面类
public class transactionAspect {
    // 定义切入点(例如:匹配com.pxq.service包下所有类的所有方法)
    @Pointcut("execution(* com.pxq.service.*.*(..))")
    public void servicePointcut() {}

    // 前置通知
    @Before("servicePointcut()")
    public void before(JoinPoint joinPoint) {
        System.out.println("方法执行前:" + joinPoint.getSignature().getName());
    }
}

xml方式:

<!-- 定义切面(若未用@Component,需手动注册) -->
<bean id="transactionAspect" class="com.pxq.aspect.transactionAspect"/>

<!-- 配置AOP切面、切入点、通知 -->
<aop:config>
    <!-- 引用切面类 -->
    <aop:aspect ref="transactionAspect">
        <!-- 定义切入点 -->
        <aop:pointcut id="servicePointcut" 
                      expression="execution(* com.pxq.service.*.*(..))"/>
        <!-- 配置前置通知 -->
        <aop:before pointcut-ref="servicePointcut" method="before"/>
    </aop:aspect>
</aop:config>

配置完aop,我们来看事务。

用简单的注解方式:

1.配置数据源和事务管理器

2.使用@Transactional标记事务方法(可以在方法上配置事务的属性)

@Configuration
@ComponentScan("com.pxq")
@EnableTransactionManagement // 开启注解驱动的事务管理
public class SpringConfig {
    // 配置数据源(以Druid为例,需引入对应依赖)
    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    // 配置事务管理器(依赖数据源)
    @Bean
    public PlatformTransactionManager transactionManager(DataSource dataSource) {
        return new DataSourceTransactionManager(dataSource);
    }
}
@Service
public class UserService {
    @Autowired
    private UserDao userDao;

    // 声明事务:默认传播行为REQUIRED,隔离级别DEFAULT
    @Transactional
    public void transferMoney(Long outUser, Long inUser, BigDecimal amount) {
        userDao.decrease(outUser, amount);
        //int n = 1/0;如果出现异常会回滚
        userDao.increase(inUser, amount);
    }
}

XML方式:

配置数据源和事务管理器

<!-- 配置数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/test"/>
    <property name="username" value="root"/>
    <property name="password" value="123456"/>
</bean>

<!-- 配置事务管理器 -->
<bean id="transactionManager" 
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

定义事务的切面切点,以及事务的属性

<!-- 配置事务通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 匹配Service层的所有方法,设置事务属性 -->
        <tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" 
                   read-only="false" rollback-for="Exception"/>
        <!-- 单独配置查询方法为只读 -->
        <tx:method name="get*" read-only="true"/>
    </tx:attributes>
</tx:advice>

<!-- AOP织入:将事务通知应用到切入点 -->
<aop:config>
    <aop:pointcut id="servicePointcut" 
                  expression="execution(* com.pxq.service.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="servicePointcut"/>
</aop:config>

可以看到aop和事务的配置有多繁琐。

如果想要给方法加事务,使用注解方法,在方法和类上加注解(一般在serviceImpl包下),需要在多处加注解,而xml却能覆盖整个包下的所有方法,虽然注解方法简单,却依然有其优势。

看完spring的配置我们来看springboot的配置

三.优化

        先引入依赖。

<!-- Spring Boot Starter(核心依赖,包含自动配置) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>

<!-- AOP依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

<!-- 事务依赖(若涉及数据库操作,需引入此依赖,包含事务管理器) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

<!-- 数据库驱动(以MySQL为例) -->
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>

    1.spring-boot-starter-aop:自动引入 AOP 相关依赖(包括aspectjweaver),并默认开启 AOP 代理(无需手动加@EnableAspectJAutoProxy)。

    2.spring-boot-starter-jdbc:引入Spring JDBC 和事务管理器(DataSourceTransactionManager),并自动配置事务支持(无需手动加@EnableTransactionManagement)

    我要提到一个重要知识点:springboot默认有很多自动配置类,比如上述的aop和事务,只要引入启动器,并开启组件扫描,自动配置类会生效。

    当你需要自定义配置类时,可以在该类上标注@Configuration,如果本身项目中有该配置类,便会覆盖默认的自动配置类,执行你自定义的配置类。

    更详细的内容web篇再来表述。

    // 1. @Aspect:标记为切面类
    // 2. @Component:纳入Spring容器管理
    @Aspect
    @Component
    public class LogAspect {
    
        // 定义切入点:匹配com.example.service包下所有类的所有方法
        // execution表达式:修饰符(可选) 返回值 包名.类名.方法名(参数)
        private static final String POINTCUT = "execution(* com.pxa.service.*.*(..))";
    
        // 环绕通知:可以在方法执行前后添加逻辑,甚至控制方法是否执行
        @Around(POINTCUT)
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            // 方法执行前
            long start = System.currentTimeMillis();
            
            // 执行目标方法(必须调用,否则目标方法不执行)
            Object result = joinPoint.proceed();
            
            // 方法执行后
            long end = System.currentTimeMillis();
            String methodName = joinPoint.getSignature().getName();
            System.out.println("方法[" + methodName + "]执行耗时:" + (end - start) + "ms");
            
            return result;
        }
    }

    事务配置:

    1.配置数据源

    yaml代码:

    yaml和properties一样写了很多基础信息,都是springboot的配置文件,但是语法不一样,都用于给配置类或组件注入具体的值。

    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC
        username: root
        password: 123456
    
    @Service
    public class UserService {
        
        private final UserMapper userMapper;
    
        // 构造器注入(防止循环依赖)
        public UserService(UserMapper userMapper) {
            this.userMapper = userMapper;
        }
    
        // 声明事务:默认传播行为REQUIRED(当前无事务则创建,有则加入)
        @Transactional
        public void transfer(Long outUser, Long inUser, BigDecimal amount) {
            // 扣减金额
            userMapper.decreaseBalance(outUser, amount);
            // 模拟异常(测试回滚)
            // if (true) throw new RuntimeException("转账失败");
            // 增加金额
            userMapper.increaseBalance(inUser, amount);
        }
    
        // 只读事务(查询方法推荐使用,提高性能)
        @Transactional(readOnly = true)
        public User getUserById(Long id) {
            return userMapper.selectById(id);
        }
    }

    其实springboot和spring写这些代码的内涵是一致的,只是springboot可以简化重复的配置内容,让开发者更高效的写代码。

    四.结尾

            下一章我将更详细的阐述自动配置类等重要的内容,帮助大家更好的看到spring和springboot的区别,和便利。

    评论
    添加红包

    请填写红包祝福语或标题

    红包个数最小为10个

    红包金额最低5元

    当前余额3.43前往充值 >
    需支付:10.00
    成就一亿技术人!
    领取后你会自动成为博主和红包主的粉丝 规则
    hope_wisdom
    发出的红包
    实付
    使用余额支付
    点击重新获取
    扫码支付
    钱包余额 0

    抵扣说明:

    1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
    2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

    余额充值