模板方法和Callback回调应用实践-自己动手写JdbcTemplate(附源码)
最近一直在研读spring源码和学习设计模式,想把自己的一些领悟与大家分享,前几天发了几篇简单的文章,可能由于文字过于简单,几次被评为新手贴,心中滴汗啊
没办法,工作太忙,大家都知道,写篇文章是要很大精力地~~~~~
今天恰有时间,把这两天的学习所得与大家分享,尽量写得详细一些,专家饶路走,新手觉得好赞一下(不要拍砖哦~~~~)。
文章源码在附件中
注:本文目的意不在“重复发明轮子”,而是借此文来探讨Spring JdbcTemplate的内部实现原理,掌握其运用精妙之处,以便在以后的“造轮运动”中能灵活运用。
话回正转,这两天在读spring的jdbc模板,对Spring源码的精妙真是佩服得五体投地,极为经典。
spring中真是集设计模式之大成,而且用得是炉火纯青。模板方法(template method)就在spring中被大量使用,如:jdbcTemplate,hibernateTemplate,JndiTemplate以及一些包围的包装等都无疑使用了模板模式,但spring并不是单纯使用了模板方法,而是在此基础上做了创新,配合callback(回调)一起使用,用得极其灵活。
OK,为了防止文章再被拍砖,我写得更详细点吧,我们首先来回顾一下模板模式:
所谓模板板式,就是在父类中定义算法的主要流程,而把一些个性化的步骤延迟到子类中去实现,父类始终控制着整个流程的主动权,子类只是辅助父类实现某些可定制的步骤。
有些抽象???
好吧,我们用代码来说话吧:
首先,父类要是个抽象类:
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识. 6 楼 jakoes 2010-07-22 finallygo 写道我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
你所提到的问题的确都是在开发过程中常遇到的。如果要把我的代码应用到企业应用中,数据链接确实要通过外部注入的。
另外一点要说明的是,如果要把上面示例运用到企业应用中,这不可能是一个“全功能的轮子”,像事物等功能肯定不是全部自己动手去写,也没有必要“重复发明轮子”。其实完全交给系统框架去管理,如Spring来管理事物等。
上面的示例意在说明模板方法的原理与使用,以后如果遇到类似场景,而没有找到“合适的轮子”的时候,就可以自己“造轮子”啦。
再次感谢楼上对本文的关注。希望有问题大家一起讨论 7 楼 finallygo 2010-07-22 说到spring,我有点小小的疑问,
我先说下我对spring的认识啊,spring中最主要的两个思想是ioc,aop
ioc就体现在工厂模式的应用,也就是说我们采用的都是面向接口的方式的编程,以后如果实现类发生变化了,可以通过修改配置文件而不用修改代码来实现系统的灵活性,但是实际上好像这种需求并不多啊,我们项目中都是一个接口,一个实现类,也就是说配置文件我们添加一个Dao的时候才去改配置文件,之后就再也不去动了,反而接口是经常变动的,因为需求是一直在增加的,所以给我的感觉就是接口成为了一个累赘,我改一个接口就要改一堆的东西(因为我们分了好几层,而一个方法的添加就从dao一直污染到顶层了),我觉得还不如直接创建一个实现类来的方便.
还有一个就是aop,我觉得主要就是用来做事务和日志的,但是这些用动态代理就可以实现了,我觉得spring太复杂了,没有必要用的
不知道我这两个思想有什么问题,麻烦你讲解一下. 8 楼 ironsabre 2010-07-23 finallygo 写道我感觉有点问题吧,首先jdbctemplate好像没有与你这里的HsqldbUtil这种类耦合在一起吧,还有一个就是,你这里好像进行了一次查询之后数据库连接就关闭了,那我怎么做事务呢?
你难道还在用连接相关的事务吗?
9 楼 blackchoc 2010-09-04 感谢楼主分享。
现在我在试着重构手头的一个项目,不幸的是这个项目已经经历了n多人,从最初到现在已经很久了。所用的技术就是楼主传说中“高手”所用的sun jdbc api。哈哈
10 楼 ironsabre 2010-09-06 blackchoc 写道感谢楼主分享。
现在我在试着重构手头的一个项目,不幸的是这个项目已经经历了n多人,从最初到现在已经很久了。所用的技术就是楼主传说中“高手”所用的sun jdbc api。哈哈
你最好的选择我认为是引入JdbcTemplate,JdbcTemplate是对直接使用jdbc api的最好升级途径。 11 楼 jakoes 2010-10-09 blackchoc 写道感谢楼主分享。
现在我在试着重构手头的一个项目,不幸的是这个项目已经经历了n多人,从最初到现在已经很久了。所用的技术就是楼主传说中“高手”所用的sun jdbc api。哈哈
那个项目应该没有使用spring框架吧,如果使用spring框架,jdbcTemplate是首选(当然是在没有使用ORM框架的情况下)。 12 楼 daquan198163 2010-10-09 finallygo 写道我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用 13 楼 finallygo 2010-10-20 daquan198163 写道finallygo 写道我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗? 14 楼 daquan198163 2010-10-20 finallygo 写道daquan198163 写道finallygo 写道我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
15 楼 xchao 2010-10-25 不错的文章,条理清晰,JAVA新手来学习了! 16 楼 finallygo 2010-10-26 daquan198163 写道finallygo 写道daquan198163 写道finallygo 写道我的耦合的意思是你不要去引用HsqldbUtil这样的类,我的意见是设置一个类型为java.sql.Connection的属性,并提供它的set方法,这样不就不会与你那个类耦合了吗?而且也提供了灵活性.因为获取连接方式是很多种的,我觉得你写在HsqldbUtil里是不太好的,你可以看spring里的虽然看起来差不多,但是它提供了setDataSource的方法吧?
我之所以会考虑事务的方面是因为我也写过自己的JdbcTemplate,但是事务处理方面却不理想,所以想看看你是怎么考虑的.而且你这样还有个不好的地方就是你每次执行查询都要重新获得一次连接吧,这样是不是太消耗资源了?
当然还是要感谢你分享你的知识.
拜托,你这个建议会害死人的。Connection不是线程安全的,绝对不能这样用
汗,线程安全不安全要看你是怎么创建这个对象的吧,如果我每次都是用new的方式来创建jdbcTemplate对象,怎么会有线程不安全之说??
就算我使用单例的,难道你不知道有ThreadLocal这个类吗?
是你自己说的“设置一个类型为java.sql.Connection的属性”,还在那狡辩。
如果调用者需要“每次都是用new的方式来创建jdbcTemplate对象”,并且set进去一个connection,调完了还要负责关连接,那还要你这个jdbcTemplate做什么呢,jdbcTemplate不就是为了封装“连接获取、关闭、异常处理”这些逻辑的么?
我没有狡辩啊,我的意思是设置不设置"一个类型为java.sql.Connection的属性"和线程俺不安全没有必然的关系,还有就是"调完了还要负责关连接",这是什么意思,我也可以在jdbcTemplate里关闭啊,为什么不能呢? 17 楼 xchao 2010-10-30 回调方法的原理、设计、实现、示例讲解的很好!
学习了!
18 楼 goolcona 2010-12-14 说一点关于类映射的相关,可以考虑使用反射在组装这个User,这样的话就不必针对每个pojo做一个JdbcTepmlateImpl。 19 楼 cai3178940 2010-12-14 写的非常好啊,支持楼主,不过还是被投了好多新手贴。。。
楼上说用反射是怎么做的呢,我觉得像楼主说的用泛型就可以不用对每个pojo做一个jdbcTemplateImpl 20 楼 whao189 2011-05-26 刚好这两天看模板方法方法模式,
看了楼主的解释 正好有助于我对此模式的理解。但是对于spring 我一直有心去研究
但是源码从哪个地方看起我还不太清楚,楼主应该看spring 有一段时间了走过去的人
了,不知道能不能指点一下我让我少走些弯路!