【框架】[Spring] 基于Spring框架的Web应用演示(附带cglib工具进行动态代理)(2)

简介: 【框架】[Spring] 基于Spring框架的Web应用演示(附带cglib工具进行动态代理)

事务

如果只代理到上面这里,写con.close方法其实会出问题的。

当然,本例很简单,servlet只请求了一个service中的一个方法,这样写没什么问题,

但是,假如我有多个service和一个service有多个方法,需要被一个用户请求servlet时同时调用时,这个连接就不能被关闭了。

因为Spring容器的事务机制的实质是对传统JDBC的封装,也即是Spring事务管理无论是对单数据库实例还是分布式数据库实例,要实现事务管理,那么必须保证在一个事务过程获得Connetion对象是同一个。

假如是servlet调用多个service或service中多个方法,需要实现的是同一个事务,我们可以:在service中写一个综合方法,在其中调用其它方法,然后给综合方法设置代理,因为这个综合方法在这里就是一个业务

,多个service,原理一样。

AOP拦截getConnection()方法,cglib工具进行动态代理Connection

然后再拦截Connection的close方法!

package cn.hncu.utils;
import java.lang.reflect.Method;
import java.sql.Connection;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodProxy;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class CloseAdvice implements MethodInterceptor{
    private ThreadLocal<Object> t = new ThreadLocal<Object>();
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        Object obj = t.get();
        if(obj==null){
            final Object con = invocation.proceed();//返回原型对象Connection
            //通过cglib工具进行动态代理
            Callback callback = new net.sf.cglib.proxy.MethodInterceptor() {
                @Override
                public Object intercept(Object proxiedObj, Method method,
                        Object[] args, MethodProxy proxy) throws Throwable {
                    if(method.getName().equals("close")){
                        return null;
                    }
                    //con为原型Connection对象
                    return method.invoke(con, args);
                }
            };
            //obj为cglib工具代理后的Connection对象
            obj=Enhancer.create(Connection.class, callback);
            t.set(obj);
        }
        return obj;
    }
}

在applicationContext.xml中配置拦截getConnection()

<bean id="conClose" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
       <property name="expression" value="execution( * *..*.*.getConnection() )"></property>
       <property name="advice">
            <bean id="advice" class="cn.hncu.utils.CloseAdvice"></bean>
       </property>
    </bean>

接下来就是要用到AOP了,拦截事务。

拦截service层的。

拦截事务的切面配置:

<!-- 自动代理 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
    <!-- 事务  切面=切点+通知 -->
    <bean id="tx" class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
        <!-- 拦截cn.hncu包下的,方法名最后为Service的任意返回值任意参数的方法 -->
        <property name="expression" value="execution (* cn.hncu..*Service.*(..) )">
        </property>
        <property name="advice">
            <bean class="cn.hncu.utils.TxAdvice"></bean>
        </property>
    </bean>

DAO层的实现类代码:

stud的实现类:

package cn.hncu.stud.dao;
import java.sql.SQLException;
import java.util.UUID;
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;
import cn.hncu.stud.domain.Book;
import cn.hncu.stud.domain.Stud;
public class StudDaoJdbc implements StudDAO{
    private DataSource dataSource = null;//依赖注入
    public DataSource getDataSource() {
        return dataSource;
    }
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    @Override
    public void saveStud(Stud stud) throws SQLException {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        stud.setS_id(uuid);
        QueryRunner run = new QueryRunner(dataSource);
        run.update("insert into stud(s_id,s_name) values(?,?)", stud.getS_id(),stud.getS_name());
    }
}

book的实现类

package cn.hncu.stud.dao;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;
import cn.hncu.stud.domain.Book;
public class BookDaoJdbc implements BookDAO{
    private DataSource dataSource = null;//依赖注入
    public DataSource getDataSource() {
        return dataSource;
    }
    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    @Override
    public void saveBook(Book book) throws SQLException {
        QueryRunner run = new QueryRunner(dataSource);
        run.update("insert into book(b_name) values(?)", book.getB_name());
    }
}

测试:

打开页面输入:

image.png

点按钮提交:

image.png

service:cn.hncu.stud.service.SaveServiceImpl@4adeee3d这个输出是我在servlet中测试一个错误的时候的输出。

再看数据库的数据:

image.png

image.png

然后,我们来测试下,事务回滚情况:

因为service层是:

@Override
    public void saveStudAndBook(Stud stud, Book book) throws SQLException {
        studDao.saveStud(stud);
        bookDao.saveBook(book);
    }

后调用bookDao的,所以,我们让saveBook挂了,改一下saveBook的方法中sql语句为:

image.png

这样,后面Book的存储肯定是出问题的。

再来测试:

image.png

点添加。

image.png

可以看到事务回滚了,但是看这里没用,我们去看下stud和book表有没有存储。当然book表肯定是不会被存储的,去看stud表就可以了:

image.png

可以看到,李四这个用户并没有被保存,证明事务起作用了。

完整项目源码链接:

–>点击访问本系列源码–

目录
打赏
0
0
0
0
988
分享
相关文章
Spring框架初识
Spring 是一个分层的轻量级开源框架,核心功能包括控制反转(IOC)和面向切面编程(AOP)。主要模块有核心容器、Spring 上下文、AOP、DAO、ORM、Web 模块和 MVC 框架。它通过 IOC 将配置与代码分离,简化开发;AOP 提供了声明性事务管理等增强功能。
90 21
Spring框架初识
Spring MVC 扩展和SSM框架整合
通过以上步骤,我们可以将Spring MVC扩展并整合到SSM框架中。这个过程包括配置Spring MVC和Spring的核心配置文件,创建控制器、服务层和MyBatis的Mapper接口及映射文件。在实际开发中,可以根据具体业务需求进行进一步的扩展和优化,以构建更加灵活和高效的企业级应用程序。
33 5
docker快速部署OS web中间件 数据库 编程应用
通过Docker,可以轻松地部署操作系统、Web中间件、数据库和编程应用。本文详细介绍了使用Docker部署这些组件的基本步骤和命令,展示了如何通过Docker Compose编排多容器应用。希望本文能帮助开发者更高效地使用Docker进行应用部署和管理。
62 19
Spring AI Alibaba 应用框架挑战赛圆满落幕,恭喜获奖选手
第二届开放原子大赛 Spring AI Alibaba 应用框架挑战赛决赛于 2 月 23 日在北京圆满落幕。
通过springboot框架创建对象(一)
在Spring Boot中,对象创建依赖于Spring框架的核心特性——控制反转(IoC)和依赖注入(DI)。IoC将对象的创建和管理交由Spring应用上下文负责,开发者只需定义依赖关系。DI通过构造函数、setter方法或字段注入实现依赖对象的传递。Spring Boot的自动配置机制基于类路径和配置文件,自动为应用程序配置Spring容器,简化开发过程。Bean的生命周期包括定义扫描、实例化、依赖注入、初始化和销毁回调,均由Spring容器管理。这些特性提高了开发效率并简化了代码维护。
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
基于Flink CDC 开发,支持Web-UI的实时KingBase 连接器,三大模式无缝切换,效率翻倍!
TIS 是一款基于Web-UI的开源大数据集成工具,通过与人大金仓Kingbase的深度整合,提供高效、灵活的实时数据集成方案。它支持增量数据监听和实时写入,兼容MySQL、PostgreSQL和Oracle模式,无需编写复杂脚本,操作简单直观,特别适合非专业开发人员使用。TIS率先实现了Kingbase CDC连接器的整合,成为业界首个开箱即用的Kingbase CDC数据同步解决方案,助力企业数字化转型。
83 5
基于Flink CDC 开发,支持Web-UI的实时KingBase 连接器,三大模式无缝切换,效率翻倍!
Python 高级编程与实战:深入理解 Web 开发与 API 设计
在前几篇文章中,我们探讨了 Python 的基础语法、面向对象编程、函数式编程、元编程、性能优化、调试技巧以及数据科学和机器学习。本文将深入探讨 Python 在 Web 开发和 API 设计中的应用,并通过实战项目帮助你掌握这些技术。
|
5月前
|
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
327 3
如何在项目中高效地进行 Web 组件化开发
高效地进行 Web 组件化开发需要从多个方面入手,通过明确目标、合理规划、规范开发、加强测试等一系列措施,实现组件的高效管理和利用,从而提高项目的整体开发效率和质量,为用户提供更好的体验。
133 63

热门文章

最新文章