使用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;
    }
}
相关推荐
火烧屁屁啦3 分钟前
【JavaEE进阶】初始Spring Web MVC
java·spring·java-ee
飞飞-躺着更舒服7 分钟前
【QT】实现电子飞行显示器(改进版)
开发语言·qt
w_312345416 分钟前
自定义一个maven骨架 | 最佳实践
java·maven·intellij-idea
岁岁岁平安19 分钟前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA22 分钟前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
北辰浮光24 分钟前
[spring]XML配置文件标签
xml·spring
Q_192849990629 分钟前
基于Spring Boot的九州美食城商户一体化系统
java·spring boot·后端
张国荣家的弟弟1 小时前
【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?
java·jar·bi
ZSYP-S1 小时前
Day 15:Spring 框架基础
java·开发语言·数据结构·后端·spring
yuanbenshidiaos1 小时前
c++------------------函数
开发语言·c++