第16章 Spring数据访问之扩展篇
本章内容
- 活用模板方法模式及Callback
- 数据访问中的多数据源
- Spring 3.0展望
16.1 活用模板方法模式及Callback
纵观第13章到第15章的内容,我们会发现不管是Spring对JDBC API的抽象,还是对Hibernate、iBATIS等ORM的集成,全部都采用了一种理念或者处理方式,那就是模板方法模式与相应的Callback接口相结合。
那么,为什么要在这里使用模板方法与Callback相结合的问题处理方式呢?最基本的原因是:不管是JDBC还是Hibemate或者其他ORM实现,在资源管理上有一个共性,那就是需要在资源使用之后可以安全地释放这些资源 。与Bitter Java所提出的理念相同, 为了确保尽可能地将资源的获取和资源的释放操作放在一起,Spring在数据访问层处理资源的问题上,采用了模板方法模式 。
这样,以一种统一而集中的方式来处理资源的获取和释放,避免了将这种容易出现问题的操作分散到代码中的各个地方,进而也就避免了由此产生的“资源泄漏”一类比较严重的问题。
推而广之,我们可以以相同的模式来处理类似的问题,而也会发现,这样的处理与我们之前的处理或者封装方式是如此的不同,如此的简洁明了。
16.1.1 FTPClientTemplate
之前我们说过,通常的FX系统会从相应的新闻提供商那里定期获取外汇交易相关新闻。最常见的方式就是,通过FTP协议到指定的FTP服务器去定期下载相应的新闻文件,所以,FX系统的应用程序需要提供相应的实现类来进行FTP操作。而程序中的FTP操作应该是比较通用的,无非就是上传下载文件。
为了程序能有一个良好的结构,我们通常会将这些FTP操作逻辑封装为一个工具类。而下面我们将看到的,就是两种截然不同的工具类实现方式。
我们不需要为最为底层的FTP操作“重新发明轮子”,Jakarta Commons Net类库提供了基本的FTP支持,不过,直接使用CommonsNet的API就与直接使用JDBC API一样让人尴尬,下方代码清单的代码演示了直接使用Commons Net API进行FTP操作的一般情况。
我得承认,FTPClient类提供的这段代码只是一段示例,不能在实际的生产环境下使用,所以,我们尝试对其进行封装。
对于使用FTPClient类实现的FTP操作来说,无非就是登录FTP服务器,传输文件,然后退出服务器三步。下方代码清单所示的FTP操作工具类是最为常见的实现方式。
相对于示例中的代码来说,通过PhaselFtpUtility类的封装,现在进行FTP操作看起来要简洁多了。不过,这样的封装方式并没有起到多少实际效果。
Phase1FtpUtility对FTPClientAPI的封装力度不够,与直接使用FTPClient的API相比,调用方只是少写几行代码而已,如下所示:
而且,这样的代码把资源的管理留给了每处调用Phase1FtpUtility进行FTP操作的调用代码。与数据库连接一样,你要怎样保证相应的资源在每处都能成功地获得释放呢?就现有的API封装方式,我们只能加强开发人员的约束力来达到正确使用API的目的了。
通常,Phase1FtpUtility的doTransfer(..)
方法用来实现具体的FTP操作逻辑,但现在的phase1FtpUtility只能提供固定的FTP操作逻辑。如果其他调用方需要不同的FTP操作,那么,或许就得子类化Phase1FtpUtility并覆写doTransfer(..)
方法了。不过,这样好像偏离了我们要将phaselFtpUtility作为单一工具类来使用的初衷。
鉴于这些限制,我们需要另一种FTPClientAPI的封装方式。而你也看出来了,就如Phase1FtpUtility所展示的那样,所有的使用FTPClient进行FTP操作的步骤几乎是一样的,唯一的不同就是每次进行FTP操作的细节。在经过JdbcTemplate、HibernateTemplate以及SqlMapClientTemplate等熏陶之后,自然而然就应该想到,我们可以对FTPClientAPI进行同样的处理,从而下方代码清单所给出的FTPClientTemplate就是我们的最终需要。
我们通过execute(FTPClientCallback)
方法对整个的基于FTPClient的API使用流程进行了封装,而将我们真正关心的每次具体的FTP操作交给了FTPClientCallback,该接口定义如下所示:
现在要做的,就是根据每次FTP操作请求细节提供相应的FTPClientCallback实现,然后交给FTPClientTemplate执行,如下所示:
FTPClientTemplate一旦构建完成,其他任何调用方都可以共享使用它,调用方每次提供自己的FTPClientCallback实现即可。
现在的FTPClientTemplate看起来可能过于单薄。某些常用的FTP操作,如文件上传、文件下载、文件列表读取等,我们可以在FTPClientTemplate内直接提供,而没有必要让调用方每次实现几乎相同的代码。
listFileNames(remoteDir,fileNamePattern)
方法就是这样的方法实现,无非就是提供了相应的FTPClientCallback实现,然后最终委托execute()
方法执行而已。
作为工具类,我们可以直接将这些常用的FTP操作方法定义到FTPClientTemplate中。如果愿意,也可以设计一个FTPOperation之类的接口,里面定义一系列的FTP操作方法,然后让FTPClientTemplate来实现该接口。
16.1.2 HttpClientTemplate
现在基于REST方式的Web服务好像比原来SOAP的方式更加受人欢迎一些,世界上许多券商或者银行通常也会以REST的方式发送一些外汇牌价之类的信息,甚至,FX系统的某些外汇新闻提供商也通过HTTP协议采用类似于REST的方式来发送新闻。那么,与基于FTP协议的信息交换类似,对于这种方式的信息交换,我们也需要在应用程序中采用适当的API进行处理。
Apache Commons HttpClient是一个提供HTTP协议支持的Java类库,许多应用包括稍后我们将提到的Spring Remoting都是采用该类库实现的。我们同样可以使用该类库进行基于HTTP协议的信息交换,或者说得更“时髦”一点儿,进行REST方式的Web服务开发。
如果你是初次接触HttpClient,那么应该先看一下HtpClient网站提供的Tutorial文档,里面给出了类似下方代码清单给出的使用代码示例。
又是获取资源、操作、释放资源、处理异常等,而且这样的代码无法用于生产环境也是肯定的了,那该怎么处理,我想你已经心里有数了吧?余下的部分,还是留给你来实现吧。