【框架】[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

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

完整项目源码链接:

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

目录
相关文章
|
11天前
|
人工智能 前端开发 API
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
Gemini Coder 是一款基于 Google Gemini API 的 AI 应用生成工具,支持通过文本描述快速生成代码,并提供实时代码编辑和预览功能,简化开发流程。
92 38
Gemini Coder:基于 Google Gemini API 的开源 Web 应用生成工具,支持实时编辑和预览
|
8天前
|
Web App开发 编解码 vr&ar
使用Web浏览器访问UE应用的最佳实践
在3D/XR应用开发中,尤其是基于UE(虚幻引擎)开发的高精度场景,传统终端因硬件局限难以流畅运行高帧率、复杂效果的三维应用。实时云渲染技术,将渲染任务转移至云端服务器,降低终端硬件要求,确保用户获得流畅体验。具备弹性扩展、优化传输协议、跨平台支持和安全性等优势,适用于多种终端和场景,特别集成像素流送技术,帮助UE开发者实现低代码上云操作,简化部署流程,保留UE引擎的强大开发能力,确保画面精美且终端轻量化。
使用Web浏览器访问UE应用的最佳实践
|
3天前
|
开发框架 运维 监控
Spring Boot中的日志框架选择
在Spring Boot开发中,日志管理至关重要。常见的日志框架有Logback、Log4j2、Java Util Logging和Slf4j。选择合适的日志框架需考虑性能、灵活性、社区支持及集成配置。本文以Logback为例,演示了如何记录不同级别的日志消息,并强调合理配置日志框架对提升系统可靠性和开发效率的重要性。
|
25天前
|
人工智能 前端开发 Java
Spring AI Alibaba + 通义千问,开发AI应用如此简单!!!
本文介绍了如何使用Spring AI Alibaba开发一个简单的AI对话应用。通过引入`spring-ai-alibaba-starter`依赖和配置API密钥,结合Spring Boot项目,只需几行代码即可实现与AI模型的交互。具体步骤包括创建Spring Boot项目、编写Controller处理对话请求以及前端页面展示对话内容。此外,文章还介绍了如何通过添加对话记忆功能,使AI能够理解上下文并进行连贯对话。最后,总结了Spring AI为Java开发者带来的便利,简化了AI应用的开发流程。
311 0
|
25天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
30天前
|
弹性计算 Java 关系型数据库
Web应用上云经典架构实践教学
Web应用上云经典架构实践教学
Web应用上云经典架构实践教学
|
20天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
64 13
|
1月前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
53 5
|
30天前
|
弹性计算 Java 数据库
Web应用上云经典架构实战
本课程详细介绍了Web应用上云的经典架构实战,涵盖前期准备、配置ALB、创建服务器组和监听、验证ECS公网能力、环境配置(JDK、Maven、Node、Git)、下载并运行若依框架、操作第二台ECS以及验证高可用性。通过具体步骤和命令,帮助学员快速掌握云上部署的全流程。
|
30天前
|
弹性计算 负载均衡 安全
云端问道-Web应用上云经典架构方案教学
本文介绍了企业业务上云的经典架构设计,涵盖用户业务现状及挑战、阿里云业务托管架构设计、方案选型配置及业务初期低门槛使用等内容。通过详细分析现有架构的问题,提出了高可用、安全、可扩展的解决方案,并提供了按量付费的低成本选项,帮助企业在业务初期顺利上云。