Spring的深入浅出(6)--使用AOP的思想改造转账案例

在Spring中使用AOP(基于注解)


使用AOP的思想改造转账案例

业务类改造:移除事务管理代码

public class AccountServiceImpl implements AccountService {
private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}

    // 转账业务逻辑(纯业务代码)
public void transfer(String source, String target, Double money) {
Account sourceAccount = accountDao.findAccountByName(source);
Account targetAccount = accountDao.findAccountByName(target);

if (sourceAccount != null && targetAccount != null) {
sourceAccount.setMoney(sourceAccount.getMoney() - money);
accountDao.updateAccount(sourceAccount);

// 模拟异常(测试事务回滚)
int num = 100 / 0;

targetAccount.setMoney(targetAccount.getMoney() + money);
accountDao.updateAccount(targetAccount);
}
}
}

优点:

  1. 移除了所有事务管理相关的代码(begin/commit/rollback)
  2. 业务逻辑更纯净,只关注核心转账功能
  3. 保留了模拟异常的代码用于测试事务回滚
  4. 符合单一职责原则,职责分离更清晰

事务管理器(切面类)

public class TransactionManager {
private ConnectionUtils connectionUtils;

    public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}

    // 开启事务
public void beginTransaction() {
try {
Connection connection = connectionUtils.getConnection();
connection.setAutoCommit(false);
} catch (SQLException e) {
throw new RuntimeException("开启事务失败", e);
}
}

    // 提交事务
public void commitTransaction() {
try {
connectionUtils.getConnection().commit();
} catch (SQLException e) {
throw new RuntimeException("提交事务失败", e);
}
}

    // 回滚事务
public void rollBackTransaction() {
try {
connectionUtils.getConnection().rollback();
} catch (SQLException e) {
throw new RuntimeException("回滚事务失败", e);
}
}

    // 关闭连接(带资源清理)
public void closeConnection() {
try {
Connection conn = connectionUtils.getConnection();
conn.setAutoCommit(true); // 恢复自动提交
conn.close(); // 实际应归还连接池
connectionUtils.removeConnection(); // 清除ThreadLocal
} catch (SQLException e) {
throw new RuntimeException("关闭连接失败", e);
}
}
}

优点:

  1. 完整的事务管理功能封装(开启/提交/回滚/关闭)
  2. 使用ConnectionUtils确保线程安全的连接管理
  3. closeConnection()中恢复自动提交状态是良好实践
  4. 异常处理升级为运行时异常,符合Spring事务管理规范

Spring AOP配置(XML方式)

        

<!-- 1. 引入AOP命名空间 -->
xmlns:aop="http://www.springframework.org/schema/aop"

<!-- 2. 定义事务管理器Bean -->
<bean id="transactionManager" class="com.xq.utils.TransactionManager">
<property name="connectionUtils" ref="connectionUtils"/>
</bean>

<!-- 3. 配置AOP -->
<aop:config>
<!-- 定义切点:AccountServiceImpl的transfer方法 -->
<aop:pointcut id="txPointcut" 
expression="execution(* com.xq.service.impl.AccountServiceImpl.transfer(..))"/>

<!-- 配置切面 -->
<aop:aspect ref="transactionManager" order="1">
<!-- 前置通知:开启事务 -->
<aop:before method="beginTransaction" pointcut-ref="txPointcut"/>

<!-- 返回通知:提交事务 -->
<aop:after-returning method="commitTransaction" pointcut-ref="txPointcut"/>

<!-- 异常通知:回滚事务 -->
<aop:after-throwing method="rollBackTransaction" 
pointcut-ref="txPointcut" 
throwing="ex"/>

<!-- 最终通知:关闭连接 -->
<aop:after method="closeConnection" pointcut-ref="txPointcut"/>
</aop:aspect>
</aop:config>

分析:

切点定义:精确匹配transfer()方法执行

通知顺序

  • before:方法执行前开启事务

  • after-returning:方法正常返回时提交

  • after-throwing:方法抛出异常时回滚

  • after:最终关闭连接(类似finally)

  • 异常处理:通过throwing="ex"捕获异常对象

事务完整性:四种通知组合确保事务的ACID特性

账户实体类(Account.java)

public class Account {
private String name;
private Double money;

    // 构造器/getter/setter
public Account() {}

    public Account(String name, Double money) {
this.name = name;
this.money = money;
}

    // 省略getter/setter
}

连接工具类(ConnectionUtils.java)

使用ThreadLocal管理连接

public class ConnectionUtils {
// 使用ThreadLocal保证线程安全
private static final ThreadLocal<Connection> tl = new ThreadLocal<>();

// 数据源(通过Spring注入)
private DataSource dataSource;

public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}

// 获取当前线程的连接
public Connection getConnection() throws SQLException {
Connection conn = tl.get();
if (conn == null) {
conn = dataSource.getConnection();
tl.set(conn);
}
return conn;
}

// 解除当前线程的连接绑定
public void removeConnection() {
tl.remove();
}
}

DAO接口以及DAO实现

public interface AccountDao {
Account findAccountByName(String name) throws SQLException;
void updateAccount(Account account) throws SQLException;
}

public class AccountDaoImpl implements AccountDao {
private QueryRunner runner;
private ConnectionUtils connectionUtils;

public void setRunner(QueryRunner runner) {
this.runner = runner;
}

public void setConnectionUtils(ConnectionUtils connectionUtils) {
this.connectionUtils = connectionUtils;
}

    @Override
public Account findAccountByName(String name) throws SQLException {
return runner.query(
connectionUtils.getConnection(),
"SELECT * FROM account WHERE name = ?",
new BeanHandler<>(Account.class),
name
);
}

    @Override
public void updateAccount(Account account) throws SQLException {
runner.update(
connectionUtils.getConnection(),
"UPDATE account SET money = ? WHERE name = ?",
account.getMoney(),
account.getName()
);
}
}

编写测试类

public class TransferTest {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
AccountService service = context.getBean("accountService", AccountService.class);

try {
// 执行转账:Tom给Jerry转500元
service.transfer("Tom", "Jerry", 500.0);
System.out.println("转账成功!");
} catch (Exception e) {
System.out.println("转账失败:" + e.getMessage());
e.printStackTrace();
}
}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/2658.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【LeetCode刷题指南】--有效的括号

&#x1f525;个人主页&#xff1a;草莓熊Lotso &#x1f3ac;作者简介&#xff1a;C研发方向学习者 &#x1f4d6;个人专栏&#xff1a; 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》 ⭐️人生格言&#xff1a;生活是默默的坚持&#xff0c;毅力是永久的…

【PyTorch】图像多分类项目

【PyTorch】图像二分类项目 【PyTorch】图像二分类项目-部署 【PyTorch】图像多分类项目 【PyTorch】图像多分类项目部署 多类图像分类的目标是为一组固定类别中的图像分配标签。 目录 加载和处理数据 搭建模型 定义损失函数 定义优化器 训练和迁移学习 用随机权重进行训…

详谈OSI七层模型和TCP/IP四层模型以及tcp与udp为什么是4层,http与https为什么是7层

一、网络模型&#xff1a;OSI七层 vs TCP/IP四层OSI七层模型 (理论参考模型):目的&#xff1a;提供一个标准化的理论框架&#xff0c;用于理解网络通信过程和各层的功能划分&#xff0c;促进不同厂商设备的互操作性。它是一个理想化的模型。分层 (从下到上):物理层&#xff1a;…

自然语言处理技术应用领域深度解析:从理论到实践的全面探索

1. 引言:自然语言处理的技术革命与应用前景 自然语言处理(Natural Language Processing,NLP)作为人工智能领域的核心分支,正在以前所未有的速度改变着我们的数字化生活。从最初的规则基础系统到如今基于深度学习的大语言模型,NLP技术经历了从理论探索到实际应用的深刻变…

Qt:qRegisterMetaType函数使用介绍

简介 在Qt中,qRegisterMetaType是一个用于向元对象系统注册自定义类型的函数。这对于需要在信号和槽中使用自定义类型(包括模板类如 std::shared_ptr)或用于排队连接(Queued Connection)非常重要。 作用: ​​使类型可用于信号与槽机制​​:特别是当信号和槽连接类型为…

《使用Qt Quick从零构建AI螺丝瑕疵检测系统》——5. 集成OpenCV:让程序拥有“视力”

目录一、概述1.1 背景介绍&#xff1a;赋予应用“视力”1.2 学习目标二、集成OpenCV2.1 安装OpenCV2.2 在Qt项目中配置CMake三、项目数据集介绍与准备四、图像的桥梁&#xff1a;ImageProvider与格式转换五、加载、转换并显示图像六、总结与展望一、概述 1.1 背景介绍&#xf…

Grafana

官网&#xff1a;https://grafana.com/zh-cn/grafana/ 文章目录GrafanaGrafana Grafana 是一个非常强大且流行的开源数据可视化和监控平台。公司能有 Grafana 平台来监控各种程序状态&#xff0c;是运维、开发和业务洞察的利器。 数据可视化&#xff1a; 这是 Grafana 的看家本…

go语言基础教程:【1】基础语法:变量

【1】基础语法 1. 注释 package mainimport "fmt"func main() {// 单行注释// 这是一个终端打印文本的功能/*这是一个多行注释这是一个多行注释这是一个多行注释*/fmt.Println("hello world!") }2. 变量 &#xff08;1&#xff09;变量的基本使用 package …

AI大模型各类概念扫盲

以下内容整理自AI&#xff0c;进行一个概念扫盲&#xff1a;Prompt&#xff08;提示词&#xff09; Prompt是用户提供给AI模型的指令或问题&#xff0c;用于引导模型生成特定输出。良好的Prompt设计能显著提升模型的任务理解能力和响应质量&#xff0c;例如通过结构化提示&…

【NLP舆情分析】基于python微博舆情分析可视化系统(flask+pandas+echarts) 视频教程 - 主页-评论用户名词云图实现

大家好&#xff0c;我是java1234_小锋老师&#xff0c;最近写了一套【NLP舆情分析】基于python微博舆情分析可视化系统(flaskpandasecharts)视频教程&#xff0c;持续更新中&#xff0c;计划月底更新完&#xff0c;感谢支持。今天讲解主页-评论用户名词云图实现 视频在线地址&…

Springmvc的自动解管理

中央转发器&#xff08;DispatcherServlet&#xff09;控制器视图解析器静态资源访问消息转换器格式化静态资源管理一、中央转发器Xml无需配置<servlet><servlet-name>chapter2</servlet-name><servlet-class>org.springframework.web.servlet.Dispatc…

JavaScript中this的5大核心规则详解

在 JavaScript 中&#xff0c;this 是一个特殊关键字&#xff0c;其值取决于函数的 调用方式 而非定义位置。它的行为遵循一套明确的规则&#xff0c;以下是核心规则和示例&#xff1a;1. 默认绑定&#xff08;独立函数调用&#xff09; 当函数独立调用时&#xff08;不作为方法…