一、前言
ioc和aop是spring的两大特点,ioc已经学习完了,那么本文将一个项目的不断改进来阐述spring实现aop的大致原理。
二、V1.0版本
(一)domain
Account.java:
1 | public class Account implements Serializable { |
(二)dao层
为了减少篇幅,只提供了添加账户和转账操作.
IAccountDao.java:
1 | /** |
AccountDaoImpl.java:
1 | public class AccountDaoImpl implements IAccountDao { |
(三)service层
IAccountService.java:
1 | public interface IAccountService { |
AccountServiceImpl.java:
1 | public class AccountServiceImpl implements IAccountService { |
仔细观察service中transfer方法的代码就会发现,当执行到35行时会产生异常,那么target的账户就不会增加,即:source账户的余额会减少,但是target账户的余额却不会增加。这在项目中是绝对不允许发生的事情。
那么有什么办法可以解决这个问题呢?
没错,我们可以手动进行事务控制。
三、V2.0版本
(一)工具类
因为在1.0版本中,转账操作这一个功能需要同时执行多个dao操作,即执行了多条sql语句,而自动事务控制的前提是每次只执行一条sql语句,因此就会出现问题。那么针对这个问题,2.0版本改进为手动进行事务控制。
但是如果需要手动进行事务控制,我们就必须确保多个操作使用的同一个Connection对象。
因此,如何确保是同一个Connection对象是关键问题。在该项目中使用ThreadLocal来实现这个目的,如下:
创建ConnectionUtils工具类:
ConnectionUtils.java:
1 | /** |
在提供一个事务管理工具类:
TransactionManager.java:
1 | /** |
(二)dao层
AccountDaoImpl.java中的代码修改为:
1 | public class AccountDaoImpl implements IAccountDao { |
(三)service层
AccountServiceImpl.java的代码修改如下:
1 | public class AccountServiceImpl2 implements IAccountService { |
通过改进之后,再进行测试时,同样会产生异常,但是我们在捕捉到异常之后会进行事务回滚,因此source账户的余额不会减少,target账户的余额不会增加。
但是我们仔细观察又会发现一个问题:进行事务控制的代码基本上都是相同的,此时,我们的代码重复度太高。
所以我们的代码还需要进行改进,我们需要把公共代码进行抽取。
四、V3.0版本
为了解决2.0版本指出的问题,本项目使用了动态代理技术。
对于代理设计模式,可以参考如下文章:
Java设计模式–代理模式【静态代理】
Java设计模式–代理模式【动态代理】
Java设计模式–代理模式【动态代理二】
(一)代理对象工具类
BeanFactory.java:
1 | /** |
(二)service层
AccountServiceImpl.java:
1 | public class AccountServiceImpl implements IAccountService { |
(三)配置
1 |
|
(四)测试
1 | .class) (SpringJUnit4ClassRunner |
五、总结
其实Spring实现aop也是使用了动态代理,因此理解本文中的代码对学习aop会有很大的帮助。
Java新手,若有错误,欢迎指正!