当前位置: 首页 > news >正文

使用Spring与JDK动态代理实现事务管理

使用Spring与JDK动态代理实现事务管理

在现代企业级应用开发中,事务管理是一项关键的技术,它可以保证一系列操作要么全部成功,要么全部失败,从而确保数据的一致性和完整性。Spring框架提供了强大的事务管理能力,但有时为了更细粒度地控制事务边界,我们可能需要自己实现事务管理逻辑。本文将介绍如何结合Spring框架和JDK动态代理技术来实现一个简单的事务管理系统。

引言

在本示例中,我们将创建一个基于Spring框架的应用程序,该程序包含一个账户服务接口(IAccountService),以及其实现类(AccountServiceImp)。为了增强该服务的事务处理能力,我们将创建一个工厂类(ProxyBeanFactory),它会为IAccountService生成一个动态代理对象,该对象能够在调用真实服务方法前后自动开启和提交事务。

XML配置

首先,我们需要配置Spring的bean定义。下面是一个简化版的Spring配置文件示例:

<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"><!-- 数据源配置略 --><!-- QueryRunner配置略 --><!-- 连接工具类配置略 --><!-- 事务工具类配置略 --><!-- 数据访问层配置略 --><!-- 业务逻辑层配置略 --><bean id="proxyService" class="org.example.service.IAccountService" factory-bean="factory" factory-method="createProxy"></bean><bean id="factory" class="org.example.factory.ProxyBeanFactory"><property name="transactionUtil" ref="transactionUtil"></property><property name="toProxyService" ref="service"/></bean><!-- 控制器配置略 --></beans>

如上所示,ProxyBeanFactory将创建一个实现了IAccountService接口的代理对象,并且会在执行业务逻辑之前和之后自动管理事务。

动态代理工厂类

接下来,我们来看一下ProxyBeanFactory类的具体实现:

package org.example.factory;import org.example.service.IAccountService;
import org.example.util.TransactionUtil;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyBeanFactory {private IAccountService toProxyService;private TransactionUtil transactionUtil;public void setToProxyService(IAccountService toProxyService) {this.toProxyService = toProxyService;}public void setTransactionUtil(TransactionUtil transactionUtil) {this.transactionUtil = transactionUtil;}public IAccountService createProxy() {return (IAccountService) Proxy.newProxyInstance(toProxyService.getClass().getClassLoader(),toProxyService.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result = null;try {transactionUtil.beginTx();result = method.invoke(toProxyService, args);transactionUtil.commitTx();} catch (Exception e) {transactionUtil.rollbackTx();} finally {transactionUtil.closeTx();}return result;}});}
}

ProxyBeanFactory类的核心在于createProxy方法,它使用JDK动态代理机制来创建代理对象。当任何IAccountService接口方法被调用时,都会触发InvocationHandler中的invoke方法,从而开启事务、执行业务逻辑并最终提交或回滚事务。

示例代码:

applicationContext.xml:

  <!-- 加载资源文件 --><context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder><!-- 注入数据源 --><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="${msg1}"/><property name="jdbcUrl" value="${msg2}"/><property name="user" value="${msg3}"/><property name="password" value="${msg4}"/></bean><bean id="queryRunner" class="org.apache.commons.dbutils.QueryRunner"><constructor-arg name="ds" ref="dataSource"/></bean><!-- 连接工具类 --><bean id="connectionUtil" class="org.example.util.ConnectionUtil"><property name="dataSource" ref="dataSource"/></bean><!-- 事务工具类 --><bean id="transactionUtil" class="org.example.util.TransactionUtil"><property name="connectionUtil" ref="connectionUtil"/></bean><bean id="mapperImp" class="org.example.dao.AccountMapperImp"><property name="queryRunner" ref="queryRunner"></property><property name="connectionUtil" ref="connectionUtil"></property></bean><bean id="service" class="org.example.service.AccountServiceImp"><property name="dao" ref="mapperImp"></property></bean><bean id="proxyService" class="org.example.service.IAccountService" factory-bean="factory" factory-method="createProxy"></bean><bean id="factory" class="org.example.factory.ProxyBeanFactory"><property name="transactionUtil" ref="transactionUtil"></property><property name="toProxyService" ref="service"/></bean><bean id="controller" class="org.example.controller.AccountControllerImp"><property name="service" ref="proxyService"></property></bean></beans>

ProxyBeanFactory:

public class ProxyBeanFactory {IAccountService toProxyService;;//装配事务工具类TransactionUtil transactionUtil;public void setAccountServiceImp(IAccountService accountServiceImp) {toProxyService = accountServiceImp;}public void setToProxyService(IAccountService toProxyService) {this.toProxyService = toProxyService;}public void setTransactionUtil(TransactionUtil transactionUtil) {this.transactionUtil = transactionUtil;}public IAccountService getAccountServiceImp() {return toProxyService;}//2.创建代理public IAccountService createProxy(){IAccountService proxy = (IAccountService) Proxy.newProxyInstance(toProxyService.getClass().getClassLoader(), toProxyService.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object obj = null;try {transactionUtil.beginTx();obj = method.invoke(toProxyService, args);transactionUtil.commitTx();} catch (Exception e) {e.printStackTrace();transactionUtil.rollbackTx();} finally {transactionUtil.closeTx();}return obj;}});return proxy;}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【最新】推荐6款论文ai写论文软件推荐网站平台
  • 【HarmonyOS NEXT星河版开发学习】小型测试案例11-购物车数字框
  • Ubantu设置国内镜像(阿里云、华为云)
  • 基于Jeecgboot3.6.3的vue3版本的流程中仿钉钉流程的鼠标拖动功能支持
  • 多模态大模型intern-vl 1.5 论文解读:How Far Are We to GPT-4V?
  • 代码随想录第二十四天|动态规划(8)
  • C#:基本语法
  • 操作ArkTS页面跳转及路由相关心得
  • 矩阵:消除冗余
  • 逻辑数仓:助企业高效、低成本、轻量级整合全域数据
  • 【MySQL】执行DDL选择Online DDL还是PT-OSC?
  • [BSidesCF 2019]Kookie1
  • 算法笔记|Day20回溯算法II
  • Jenkins部署java项目
  • JAVA集中学习第四周学习记录(三)
  • android高仿小视频、应用锁、3种存储库、QQ小红点动画、仿支付宝图表等源码...
  • ECMAScript入门(七)--Module语法
  • LeetCode刷题——29. Divide Two Integers(Part 1靠自己)
  • php ci框架整合银盛支付
  • Promise面试题,控制异步流程
  • quasar-framework cnodejs社区
  • spring-boot List转Page
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • 从重复到重用
  • 观察者模式实现非直接耦合
  • 记录:CentOS7.2配置LNMP环境记录
  • 简析gRPC client 连接管理
  • 十年未变!安全,谁之责?(下)
  • 手机端车牌号码键盘的vue组件
  • 一加3T解锁OEM、刷入TWRP、第三方ROM以及ROOT
  • 用Python写一份独特的元宵节祝福
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • HanLP分词命名实体提取详解
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • 选择阿里云数据库HBase版十大理由
  • ​flutter 代码混淆
  • ​sqlite3 --- SQLite 数据库 DB-API 2.0 接口模块​
  • #565. 查找之大编号
  • $nextTick的使用场景介绍
  • ()、[]、{}、(())、[[]]命令替换
  • (JS基础)String 类型
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (PyTorch)TCN和RNN/LSTM/GRU结合实现时间序列预测
  • (补)B+树一些思想
  • (补充)IDEA项目结构
  • (第二周)效能测试
  • (二十九)STL map容器(映射)与STL pair容器(值对)
  • (力扣)1314.矩阵区域和
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (四)js前端开发中设计模式之工厂方法模式
  • (万字长文)Spring的核心知识尽揽其中
  • (小白学Java)Java简介和基本配置
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)