论坛首页 Java版 DAO

一种用动态proxy自动实现dao接口的减少代码的方法

浏览 19590 次
该帖已经被评为精华帖
作者 正文
时间:2006-04-11
2006/5/22: 现在关于daozero的版本升级等消息另开了个帖子,见http://forum.javaeye.com/viewtopic.php?t=20477
这里先用一句话说明一下daozero:daozero通过自动实现一个daozero接口来减少dao的代码


想了一个方法来来减少dao代码,sourceforge上注册成功了,现在可以到http://sourceforge.net/projects/dao-zero下载, 大家多提提意见,把它完善了,说不定真能有些用处。

前提条件:使用iBatis,用一个statement的名字来代表一个(组)SQL;而DAO接口的方法名必须与statement名字一一对应;
推荐条件:使用Spring,允许用一个FactoryBean生成一个实现了DAO接口的动态proxy

思路:DAO接口的方法名与statement名字一一对应,所以可以在动态proxy的invoke()方法中截获对DAO接口方法的调用,用方法名作为statement名,用方法的参数组成statement的parameter map,然后就可以调用iBaits的queryForObject()等API了。这样,许多dao接口的实现代码就可以不需要了,定义一个DAO接口,一个Spring Bean和一个SQL mapping xml文件即可。
当然,有时候还是需要允许手工写的DAO代码覆盖这个动态proxy接口的,所以可以让这个动态proxy只拦截abstract方法。所以我视被proxy的类是否是接口分别用jdk的proxy和cglib的enhancer实现。
不过,因为iBatis API不提供其statement的meta data,所以现在的实现代码中hack了iBatis的API,感觉不好。
大家觉得值得讨论的话我争取明天晚上整理好代码传上来。
   
时间:2006-04-12
比如拿spring的jpetstore中的用户账号接口来说
[code:1]
public interface AccountDao {

Account getAccountByUsername(String username) throws DataAccessException;

List getUsernameList() throws DataAccessException;
//其他方法省略
}
[/code:1]
它使用到的iBatis SQL Mapping XML如下:
[code:1]<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQL Map 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap namespace="Account">

<resultMap id="result" class="daozero.sample.jpetstore.domain.Account">
<result property="username" column="userid" columnIndex="1"/>
<result property="email" column="email" columnIndex="2"/>
<!-- 其它属性声明省略 -->
</resultMap>

<select id="getAccountByUsername" resultMap="result">
select
signon.username as userid,
account.email, account.firstname,
account.lastname, account.status,
account.addr1, account.addr2,
account.city, account.state,
account.zip, account.country,
account.phone, profile.langpref,
profile.favcategory, profile.mylistopt,
profile.banneropt, bannerdata.bannername
from account, profile, signon, bannerdata
where account.userid = #value#
and signon.username = account.userid
and profile.userid = account.userid
and profile.favcategory = bannerdata.favcategory
</select>

<select id="getUsernameList" resultClass="java.lang.String">
select username as value from signon
</select>

<!- 其它statement声明省略 -->

</sqlMap>[/code:1]
   
0 请登录后投票
时间:2006-04-12
在spring bean定义中这么定义
[code:1]
<bean id="baseDao" abstract="true" class="daozero.Dao">
<property name="sqlMapClient" ref="sqlMapClient"/>
</bean>

<bean id="accountDao" parent="baseDao">
<property name="targetType" value="org.springframework.sample.jpetstore.dao.ibatis.auto.SqlMapAccountDao" />
<property name="namespace" value="Account"/>
</bean>
[/code:1]
其中daozero.Dao就是我说的能自动实现dao接口的动态proxy。
在这个例子中,对于accountDao这个bean来说,它只需要定义一个将接口类型[code:1]org.springframework.sample.jpetstore.dao.ibatis.auto.SqlMapAccountDao[/code:1]
设到bean的属性targetType即可,一行实现类代码都不需要。
   
0 请登录后投票
时间:2006-04-12
这个方案看起来很过瘾...
没有啥建设性意见,还是赞楼主一个!
等待后续....
   
0 请登录后投票
时间:2006-04-12
真正自己写的source只是daozero一个包。
jpetstore的例子是改自spring 1.2.7带的那个jpetstore例子。
自己感觉是有些实用价值的(虽然很小),准备放到sourceforge上去,所以,已经写上了一些license声明(APL 2.0)

带了很多库文件,还自带了ant,所以压缩后还有5.8兆之多,所以只能用rar分成几个文件分别上传。

第一个文件是exe,所以如果担心中病毒就别双击直接执行,用鼠标右键的Open With WinRAR打开就可以了(废话?:) )。

使用方法:解开后看根目录下的readme.txt中。
   
0 请登录后投票
时间:2006-04-12
第一个文件。没有rar的话可以把这第一个文件的后缀名(rar)改成exe,再双击执行。
   
0 请登录后投票
时间:2006-04-12
用zip显得更像专业的open source
   
0 请登录后投票
时间:2006-04-12
liusong1111 写道
用zip显得更像专业的open source
:D

是啊,可是rar压缩效率高啊,拆分也方便。
弄到sourceforge的话会考虑搞成zip的。
   
0 请登录后投票
时间:2006-04-12
part 2
   
0 请登录后投票
时间:2006-04-12
part 3
   
0 请登录后投票
论坛首页 Java版 DAO

跳转论坛:
JavaEye推荐