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

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

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

引言

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

XML配置

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

xml 复制代码
<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类的具体实现:

java 复制代码
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() {
                    @Override
   public 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:

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:

java 复制代码
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() {
            @Override
            public 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;
    }
}
相关推荐
JinSo5 分钟前
国际化探索:颗粒化方案
前端·javascript·设计模式
当归10249 分钟前
微服务与消息队列RabbitMQ
java·微服务
IT猿手10 分钟前
2025最新群智能优化算法:云漂移优化(Cloud Drift Optimization,CDO)算法求解23个经典函数测试集,MATLAB
开发语言·数据库·算法·数学建模·matlab·机器人
Lx35211 分钟前
《从头开始学java,一天一个知识点》之:循环结构:for与while循环的使用场景
java·后端
至暗时刻darkest14 分钟前
go mod文件 项目版本管理
开发语言·后端·golang
Cache技术分享15 分钟前
15. Java 如何声明一个变量来引用数组
java·前端
雷渊15 分钟前
深入分析理解mysql的MVCC
java·数据库·面试
知其然亦知其所以然16 分钟前
Java 高级面试题:Lock 到底比 synchronized 强在哪?
java·后端·面试
风象南19 分钟前
Spring Boot 的 20个实用技巧
java·spring boot
Java陈序员19 分钟前
IDEA 必备插件!轻松搞定 JSON 格式化!
java·json·intellij idea