使用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;
    }
}
相关推荐
P.H. Infinity几秒前
【RabbitMQ】04-发送者可靠性
java·rabbitmq·java-rabbitmq
生命几十年3万天4 分钟前
java的threadlocal为何内存泄漏
java
caridle16 分钟前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
萧鼎19 分钟前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸20 分钟前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农20 分钟前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^21 分钟前
数据库连接池的创建
java·开发语言·数据库
苹果醋325 分钟前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
秋の花29 分钟前
【JAVA基础】Java集合基础
java·开发语言·windows
小松学前端32 分钟前
第六章 7.0 LinkList
java·开发语言·网络