论坛首页 Java企业应用论坛

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

浏览 31221 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-04-11  
DAO
2006/5/22: 现在关于daozero的版本升级等消息另开了个帖子,见http://forum.iteye.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中的用户账号接口来说
public interface AccountDao {

  Account getAccountByUsername(String username);                        throws DataAccessException; 

	List getUsernameList(); throws DataAccessException;
    //其他方法省略
}

它使用到的iBatis SQL Mapping XML如下:
<?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>
0 请登录后投票
   发表时间:2006-04-12  
在spring bean定义中这么定义
	
<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>

其中daozero.Dao就是我说的能自动实现dao接口的动态proxy。
在这个例子中,对于accountDao这个bean来说,它只需要定义一个将接口类型
org.springframework.sample.jpetstore.dao.ibatis.auto.SqlMapAccountDao

设到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

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

跳转论坛:
Global site tag (gtag.js) - Google Analytics