使用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;
    }
}
相关推荐
null or notnull27 分钟前
java服务器空间不够时:将多个服务器的文件存放至同一个服务器上(使用映射器的办法)
java·运维·服务器·java-ee
代码栈上的思考41 分钟前
JVM中内存管理的策略
java·jvm
YoungP1 小时前
【Effective Java 条目二】-- 当构造器参数较多时考虑使用生成器
java
野生技术架构师1 小时前
牛客网Java 高频面试题总结(2025最新版)
java·开发语言·面试
一只鹿鹿鹿1 小时前
系统安全设计方案书(Word)
开发语言·人工智能·web安全·需求分析·软件系统
纪莫1 小时前
技术面:SpringBoot(springboot的类加载和传统的双亲委派有什么区别、如何按顺序实例化Bean)
java·spring·java面试⑧股
持梦远方1 小时前
【C++日志库】启程者团队开源:轻量级高性能VoyLog日志库完全指南
开发语言·c++·visual studio
聪明努力的积极向上1 小时前
【C#】HTTP中URL编码方式解析
开发语言·http·c#
曾经的三心草2 小时前
springcloud二-Seata3- Seata各事务模式
后端·spring·spring cloud
kyle~2 小时前
CPU调度---协程
java·linux·服务器·数据库·c++20