Spring入门——AOP分析

本文通过模拟转账案例,深入解析AOP(面向切面编程)与事务管理在Java中的应用。探讨了如何通过ThreadLocal实现连接复用,解决多事务独立问题,并引入动态代理简化代码,增强功能。

在这里插入图片描述通过这几步骤来学习aop

我们通过一个模拟转账的案例来学习
Service接口
在这里插入图片描述ServiceImpl实现类
在这里插入图片描述Dao接口
在这里插入图片描述DaoImpl实现类
在这里插入图片描述测试类
在这里插入图片描述然后基本的bean 数据源通过xml配置后 ,现在可以实现基本的转账


存在什么问题???
如果我们在更新数据里插入一个异常
那么就会发生 前一个转出钱事件完成 而后一个转入钱因为这个异常而没有发生
在这里插入图片描述
那么发生这个的原因是什么?
是没有事务吗? 事实上这里是有事务的 ,例如之前普通的增删改查 这些操作都是能运行的 说明这些都是可以连接数据库的,这些事务的运行是没有问题的
问题出在这里转账中 调用了多个事务 而每个事务都是独立与数据库连接
在这里插入图片描述当某一个连接因为一个异常而中断后 就无法运行
那么我们要怎么让这个问题得到解决呢 — 让多个事务用同一个连接connection
怎么实现呢—用ThreadLocal对象把connection和当前线程绑定,从而使一个线程只有一个能控制事务的对象----即这些操作(线程)里面只有一个connection去和数据库连接,要发生就全部发生,要不发生就全部不发生
在这里插入图片描述如何操作呢?第一步想到的应该是事务控制,即把连接数据库和线程绑定
创建一个连接数据库的工具类
在这里插入图片描述在这里插入图片描述1,先要定义一个ThreadLocal,可以从中获得连接,如果以前已经建立了连接那就直接返回,没有之前没有建立连接,那么就这次建立与数据库的连接,那么就要定义数据源,而数据源又要用xml配置的数据源通过set方法注入,然后就可以得到与数据库的连接,放进ThreadLoal,这样之后几次需要连接拿出来的就是这次存进去的,那么就实现了进程(同一个进程)与连接(同一个连接)的绑定
2.接下来我们就要去配置事务管理相关的工具类
怎么配置呢?要先拿到连接 那么就要先定义(创建)刚刚那个拿到连接的工具类(当然不是用new 而是一样用set方法等Spring注入)在这里插入图片描述
然后用里面的方法得到连接的方法,得到连接后就可以开始用事务方法了
有commit(),rollback()等等
在这里插入图片描述在这些事务方法中其实有个小细节
注意:我们的这些连接是使用了连接池,连接池的好处就是在我们把消耗时间的连接操作都放在应用加载开始的时候执行完,在Web应用中,当我们开启tomcat,加载应用的时候就把一些连接创建了,在后续需要连接的时候就不用再去数据库连接了,同理在服务器方面,也会有一个叫做线程池,类似连接池一样当我们释放的时候,就是把连接 / 线程返回到连接池 / 线程池,那么实际上我们并没有关闭掉这个线程和连接的绑定,只是线程回到了线程池,那么下次用connection获得连接的时候,是可以获得的只是已经用不了了,所以我们不仅要close(丢回池里),也要解绑(接触与连接的绑定)
在连接的工具类中加上解绑操作
在这里插入图片描述
在释放事务上 不仅调用close也要调用解绑remove操作
在这里插入图片描述


创建了获得连接的工具类,也创建了事务控制类
那么我们就可以在事务层添加事务控制方法
所以先要在事务层实现类中定义事务控制类 同理要用set注入
然后就可以把事务控制方法都放在原来的事务方法中
在这里插入图片描述在这里插入图片描述


那么我们已经把方法都写好了 就要开始配置了
因为之前我们已经打算把从数据库取得的连接 这种操作去掉(要用connection那种和线程绑定的取才行),那么我们就要把数据库里面以前配置的取连接的配置去掉
在这里插入图片描述但是我们在Dao层与对数据库进行增删改查的操作也要取数据库连接,所以我们也要取Dao层定义Connection 让那些操作也用这种绑定线程的去链接操作
在这里插入图片描述并且把每个query方法中也用其中一种重载方法(把连接放在第一个参数)
在这里插入图片描述继续配置
1.connection 里面用到 数据源
在这里插入图片描述
2.事务管理器 里面用到 connection
在这里插入图片描述
3.Dao 里面用到了connection![述](https://img-blog.csdnimg.cn/20191204234157440.png)
4.Service 里面用到了事务管理器
在这里插入图片描述


这样我们就配置完了 也加入了事务控制的功能
这时候就会发现我们的代码变得非常冗长 不仅在Service加事务控制方法时有大量的重复代码,而且每个类如果要用其他类就要set注入,对应的xml也要配置注入 而且这里也存在严重的依赖(之前讲过依赖分为类之间和方法之间),在这里 如果我们把事务控制方法的名字改一下 那么Service用过该事务控制方法都要跟着改,这个就是方法间的依赖

那我们要怎么解决这些问题呢----动态代理
因为我们每个Service的方法都要进行事务控制(增强了功能),而且我们又不想在那些Service方法里面每个都手动加(依赖),这时候就可以用动态代理,代理了那个类,动态生成代理类,然后那些方法都可以增强,而且只需要写一个增强模板(AOP的切面 / 代理的invoke方法)

在这里插入图片描述在这里插入图片描述前面两个参数都是固定写法,最主要的是后面的这个用于增强的代码编写
它就是匿名内部类,我们只需要编写这个invoke方法
在这里有个method.invoke(produce,args);就是原方法什么都没有增强
在这里插入图片描述我们用了一个代理商赚差价的方式来模拟这个动态代理
先用money获得原来方法的参数,也就是消费者给的钱10000
然后通过判断是否是“saleProduct方法” 如果是就赚取0.2的差价,把0.8的钱返回给工厂,这就实现了对这个销售的增强,如果不是“saleProduct"则直接返回null
在这里插入图片描述


这种动态代理是基于接口的 如果该类没有继承接口 那么我们就要用基于子类的
基于子类的动态代理
要加入第三方依赖包
在这里插入图片描述
然后把被代理类的接口去掉,这是基于子类的写法
在这里插入图片描述
在这里插入图片描述在这里插入图片描述


可以把这个思想整合到刚开始的那个转移金钱的事务里面
那么就是Service实现类的对象调用这些增删改查是加自己配置的事务控制方法,这样很麻烦的话,我们就要对这个对象进行代理,那么我们就要一个工厂取获得代理对象在这里插入图片描述
这个工厂要拿到被代理对象 那么也就要用set注入的方式
然后创建返回代理对象方法,方法里面开始用动态代理 并把代理成功的对象返回
然后把我们之前写的事务控制方法丢进去(事务控制方法用到了事务控制类 也要用set注入)
在这里插入图片描述在这里插入图片描述

现在执行Service里面的任何方法都会被代理拦截 然后执行的是代理对象的方法,那么就有事务控制了

那么同理我们也要修改一下我们的xml
1.原Service的事务控制类就可以去掉了
2.以及配置了一个获得代理的类工厂 其中注入了Service和事务管理器
3.而且我们的代理类 也是通过这个获得代理类的工厂
在这里插入图片描述
这时候我们就有两个Service类型的类(实现同一接口),一个是代理的一个是原来的,所以我们在Test测试类的时候创建的Service类对象就不能自动选择哪一个了 因为类型一样 要配置id(去调用代理对象)
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值