银⾏转账案例界⾯
银⾏转账案例表结构
银⾏转账案例代码调⽤关系
银⾏转账案例关键代码
TransferServlet
1 | package com.lagou.edu.servlet; |
TransferService接⼝及实现类
1 | package com.lagou.edu.service; |
1 | package com.lagou.edu.service.impl; |
AccountDao层接⼝及基于Jdbc的实现类
1 | package com.lagou.edu.dao; |
JdbcAccountDaoImpl(Jdbc技术实现Dao层接⼝)
1 | package com.lagou.edu.dao.impl; |
银⾏转账案例代码问题分析
- 问题⼀:在上述案例实现中,service 层实现类在使⽤ dao 层对象时,直接在TransferServiceImpl 中通过 AccountDao accountDao = new JdbcAccountDaoImpl() 获得了 dao层对象,然⽽⼀个 new 关键字却将 TransferServiceImpl 和 dao 层具体的⼀个实现类JdbcAccountDaoImpl 耦合在了⼀起,如果说技术架构发⽣⼀些变动,dao 层的实现要使⽤其它技术,⽐如 Mybatis,思考切换起来的成本?每⼀个 new 的地⽅都需要修改源代码,重新编译,⾯向接⼝开发的意义将⼤打折扣?
- 问题⼆:service 层代码没有竟然还没有进⾏事务控制 ?!如果转账过程中出现异常,将可能导致数据库数据错乱,后果可能会很严重,尤其在⾦融业务。
问题解决思路
- 针对问题⼀思考:
- 实例化对象的⽅式除了 new 之外,还有什么技术?反射 (需要把类的全限定类名配置在xml中)
- 考虑使⽤设计模式中的⼯⼚模式解耦合,另外项⽬中往往有很多对象需要实例化,那就在⼯⼚中使⽤反 射技术实例化对象,⼯⼚模式很合适
- 更进⼀步,代码中能否只声明所需实例的接⼝类型,不出现 new 也不出现⼯⼚类的字眼,如下? 能!声明⼀个变量并提供 set ⽅法,在反射的时候将所需要的对象注⼊进去吧
1
2
3
4
5
6
7
8
9public class TransferServiceImpl implements TransferService {
// 仅仅声明dao层接口
private AccountDao accountDao;
// 提供set方法供外部注入dao层实现类对象
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
} - 针对问题⼆思考:
- service 层没有添加事务控制,怎么办?没有事务就添加上事务控制,⼿动控制 JDBC 的Connection 事务,但要注意将Connection和当前线程绑定(即保证⼀个线程只有⼀个Connection,这样操作才针对的是同⼀个 Connection,进⽽控制的是同⼀个事务)
案例代码改造
针对问题⼀的代码改造
beans.xml
1 |
|
增加 BeanFactory.java
1 | package com.lagou.edu.factory; |
修改 TransferServlet
1 |
|
修改 TransferServiceImpl
1 | public class TransferServiceImpl implements TransferService { |
针对问题⼆的改造
增加 ConnectionUtils
1 | package com.lagou.edu.utils; |
增加 TransactionManager 事务管理器类
1 | package com.lagou.edu.utils; |
增加 ProxyFactory 代理⼯⼚类
1 | package com.lagou.edu.factory; |
修改 beans.xml
1 |
|
修改 JdbcAccountDaoImpl
1 | package com.lagou.edu.dao.impl; |
修改 TransferServlet
1 | package com.lagou.edu.servlet; |