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

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

完整项目源码链接:

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

目录
相关文章
|
2天前
|
设计模式 开发框架 数据库
Python Web开发主要常用的框架
【5月更文挑战第12天】Python Web开发框架包括Django、Flask、Tornado和Pyramid。Django适用于复杂应用,提供ORM、模板引擎等全套功能;Flask轻量级,易于扩展,适合小型至中型项目;Tornado擅长处理高并发,支持异步和WebSockets;Pyramid灵活强大,可适配多种数据库和模板引擎,适用于各种规模项目。选择框架需依据项目需求和技术栈。
14 2
|
3天前
|
Java 应用服务中间件 测试技术
深入探索Spring Boot Web应用源码及实战应用
【5月更文挑战第11天】本文将详细解析Spring Boot Web应用的源码架构,并通过一个实际案例,展示如何构建一个基于Spring Boot的Web应用。本文旨在帮助读者更好地理解Spring Boot的内部工作机制,以及如何利用这些机制优化自己的Web应用开发。
15 3
|
4天前
|
安全 Java 开发者
深入理解Spring Boot配置绑定及其实战应用
【4月更文挑战第10天】本文详细探讨了Spring Boot中配置绑定的核心概念,并结合实战示例,展示了如何在项目中有效地使用这些技术来管理和绑定配置属性。
11 1
|
23小时前
|
开发框架 监控 Java
深入探索Spring Boot的监控、管理和测试功能及实战应用
【5月更文挑战第14天】Spring Boot是一个快速开发框架,提供了一系列的功能模块,包括监控、管理和测试等。本文将深入探讨Spring Boot中监控、管理和测试功能的原理与应用,并提供实际应用场景的示例。
14 2
|
1天前
|
机器学习/深度学习 JSON 编译器
C++ 资源大全:标准库、Web框架、人工智能等 | 最全整理
C++ 资源列表,内容包括: 标准库、Web应用框架、人工智能、数据库、图片处理、机器学习、日志、代码分析等
14 1
|
3天前
|
Go
golang学习3,golang 项目中配置gin的web框架
golang学习3,golang 项目中配置gin的web框架
|
5天前
|
Java Spring 容器
深入理解Spring Boot启动流程及其实战应用
【5月更文挑战第9天】本文详细解析了Spring Boot启动流程的概念和关键步骤,并结合实战示例,展示了如何在实际开发中运用这些知识。
17 2
|
7天前
|
JavaScript Java 开发者
Spring Boot中的@Lazy注解:概念及实战应用
【4月更文挑战第7天】在Spring Framework中,@Lazy注解是一个非常有用的特性,它允许开发者控制Spring容器的bean初始化时机。本文将详细介绍@Lazy注解的概念,并通过一个实际的例子展示如何在Spring Boot应用中使用它。
19 2
|
14天前
|
XML Java 数据格式
如何在Spring AOP中定义和应用通知?
【4月更文挑战第30天】如何在Spring AOP中定义和应用通知?
17 0
|
14天前
|
中间件 Go API
【Go 语言专栏】Go 语言中的 Web 框架比较与选择
【4月更文挑战第30天】本文对比了Go语言中的四个常见Web框架:功能全面的Beego、轻量级高性能的Gin、简洁高效的Echo,以及各自的性能、功能特性、社区支持。选择框架时需考虑项目需求、性能要求、团队经验和社区生态。开发者应根据具体情况进行权衡,以找到最适合的框架。