论坛首页 Java企业应用论坛

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

浏览 31219 次
该帖已经被评为精华帖
作者 正文
   发表时间:2006-05-16  
这个小东西是我做的1个方便基于ibatis+spring开发的小工具,大家鼓励我会更有干劲继续下去!请大家尽情提意见。

iBatis 的实际应用中,其实工作量大的不是在于dao-zero关注的代码部分,而是写sql statement,但是我自己的观点是只要代价不大,能机器做的就不要人工做--程序员应该把精力放在机器所不能完成的事情上,别去做繁复的事情。 dao-zero的使用方法简单,几乎不用配置,而且所要求的statement名与方法名保持一致等约定遵守起来也很容易,再者,得益于cglib,也允许混合使用原来的iBatis API,所以我有了 dao-zero这个想法以后,就认为它容易实现,容易使用,值得公开给大家试试。

从包括其他地方得到的反馈来看,喜欢用户代码生成的不少,代码自动生成在具体应用时有一定针对性,但是个人认为因为难有普遍性,只能流传于创建者周围(比如公司/项目),因为往往会太细节化而导致使用者不得不深入了解模板。
0 请登录后投票
   发表时间:2006-10-16  
0 请登录后投票
   发表时间:2007-01-12  
我正在做[url=http://www.iteye.com/topic/28791]jxyz[/url]的0.2版,在他的扩展里面添加了对Ibatis的GenericDAO的支持,这样,对于Ibatis的操作也可以将一般的mvc5个类减少到3个类了,值得得意吗?不!我看到了dao-zero,这时我发现我可以把3个类减少到1个类,而且还是接口,当然,这要使用dao-zero了,具体思路如下:做一个IGenericLoigc
public interface IGenericLogic <Obj,Id>{
   //基本curd方法,略
}

一个User domain
  public class User{
    String email;
    String name;//pk
    String passwd;
}

一个IUserGeneric

public IUserLogic extends IGenericLogic<User,String>{
}

ibtis和spring配置见zero-dao
http调用
http://localhost/IUserLogic!doInsert.xyz?email=email&name=name&passwd=passwd
testcase调用


不错,不过,dao-zero留下hibernate和ejb的我认为大可不必,没有太大意义,也不可能做到那个程度,hibernate如果都用namedquery,把hql都写到hbm文件中才有可能,那样,就不是hibernate了
0 请登录后投票
   发表时间:2007-01-15  
由于我使用了泛型,我必须得到DAO接口的具体接口类,但是我通过SpringBean得不到

			Object handle = Proxy.getInvocationHandler(daoBean);
			Field field = handle.getClass().getDeclaredField("advised");
			field.setAccessible(true);
			AdvisedSupport advised = (AdvisedSupport) field.get(handle);
			Object realObject = advised.getTargetSource().getTarget();
			Object autoProxy = Proxy.getInvocationHandler(realObject);
			return autoProxy;

我只能得到daozero.ibatis.AutoProxy;
然后还想使用反射,但是AutoProxy的m_dao就是null,没办法,我加了一个类,
package daozero.ibatis;

import java.util.HashMap;
import java.util.Map;

public class DAOClass {

	private static Map<Object,Class> DAO_CLASS_MAP=new HashMap<Object,Class>();
	
	public static Class getClass(Object autoProxy){
		return DAO_CLASS_MAP.get(autoProxy);
	}
	
	public static void putClass(Object autoProxy,Class clasz){
		DAO_CLASS_MAP.put(autoProxy,clasz);
	}

}

在AutoProxy的构造函数末尾添加一行
DAOClass.putClass(this,_dao.getTargetType());
这样就能得到DAO的接口了,可是这种做法太糟糕,我还没有找到好方法,请教楼主了!
0 请登录后投票
   发表时间:2007-01-15  
好了,找到了,还是反射:
			Object handle = Proxy.getInvocationHandler(autoProxy);
			Field field = handle.getClass().getDeclaredField("m_executors");
			field.setAccessible(true);
			Map map = (Map) field.get(handle);
			Object iExecutor=null;
			for(Iterator it=map.entrySet().iterator();it.hasNext();){
				Map.Entry entry=(Map.Entry)it.next();
				iExecutor=entry.getValue();
				break;
			}
			Class abstruct=iExecutor.getClass().getSuperclass().getSuperclass();
			Method method=abstruct.getDeclaredMethod("getExecuteContext",null);
			method.setAccessible(true);
			ExecuteContext ec=(ExecuteContext)method.invoke(iExecutor,null);
			Method daomethod=ExecuteContext.class.getDeclaredMethod("getDao",null);
			daomethod.setAccessible(true);
			Dao dao=(Dao)daomethod.invoke(ec,null);
			return dao.getTargetType();
0 请登录后投票
   发表时间:2007-01-16  
支持一个。
0 请登录后投票
   发表时间:2007-01-24  
很抱歉!很久没来javaeye,刚看到你的帖子。

zhouxuanyi 写道
由于我使用了泛型,我必须得到DAO接口的具体接口类,但是我通过SpringBean得不到

			Object handle = Proxy.getInvocationHandler(daoBean);
			Field field = handle.getClass().getDeclaredField("advised");
			field.setAccessible(true);
			AdvisedSupport advised = (AdvisedSupport) field.get(handle);
			Object realObject = advised.getTargetSource().getTarget();
			Object autoProxy = Proxy.getInvocationHandler(realObject);
			return autoProxy;

我只能得到daozero.ibatis.AutoProxy;
然后还想使用反射,但是AutoProxy的m_dao就是null,没办法,我加了一个类,
package daozero.ibatis;

import java.util.HashMap;
import java.util.Map;

public class DAOClass {

	private static Map<Object,Class> DAO_CLASS_MAP=new HashMap<Object,Class>();
	
	public static Class getClass(Object autoProxy){
		return DAO_CLASS_MAP.get(autoProxy);
	}
	
	public static void putClass(Object autoProxy,Class clasz){
		DAO_CLASS_MAP.put(autoProxy,clasz);
	}

}

在AutoProxy的构造函数末尾添加一行
DAOClass.putClass(this,_dao.getTargetType());
这样就能得到DAO的接口了,可是这种做法太糟糕,我还没有找到好方法,请教楼主了!


m_dao始终是null这应该是个bug,只需在AutoProxy的constructor里加上
		m_dao = _dao;
就可以了。

但是这种用反射的方法我还是觉着不合适,因为这样你就依赖于sun jdk的proxy内部实现了,而且这个方法好像只能处理接口的proxy,如果dao是一个abstract class,dao-zero是用cglib来生成proxy的。即使你无需考虑处理abstract class,还是会有问题 -- 因为我一直想统一起来,都用cglib处理呢

所以,我这两天会给dao-zero增加个功能,思路是给生成的daoBean加一个IMetaData接口,
public interface IMetaData {
	Class getDaozeroTargetType();//这就是你需要的吧?
	Object getDaozeroTargetDao();
	Map getDaozeroTargetProperties();
	String getDaozeroTargetNamespace();	
}


可是,可能我没看明白,但是daoBean.getClass()难道不是你需要的吗?如果是因为想要的是interface,那么daoBean.getClass().getInterfaces()也就可以了。

另外,赞一句xyz。虽然我不喜欢其中一些细节,但是xyz的基本思路还是很有创意的。
0 请登录后投票
   发表时间:2007-01-25  
没明白怎么把方法参数转换为ibatis的Map的。莫非能拿到参数名字?
0 请登录后投票
   发表时间:2007-01-25  
ajoo 写道
没明白怎么把方法参数转换为ibatis的Map的。莫非能拿到参数名字?

是很笨的方法,有两种处理方法:
1.如果可用作ibatis map参数的方法参数只有一个而且本身类型就是Map或是个java bean,就把这个方法参数直接传给ibatis。
2.如果可用作ibatis map参数的方法参数有多个,就new一个map出来,把这些方法参数作为map entry的value,而把ibatis statement中找到的parameter的名字作为map entry的key。这里面的问题就是你所说的怎么找到对应某个方法参数的ibatis statment的parameter,处理方式就笨在这里:用双方的声明的顺序来找到对应关系。
拿到参数名字在class里含有debug信息时是可能的,但显然release版本不能依赖debug信息。
也可以像jxyz那样给每一个方法参数加上annotation,用annotation指定名字,但现在还没做,因为得到的反馈是大部分人的使用方法是就传一个java bean,那么1.就够用了。再有就是这么做就只能用在jdk1.5上了,所以优先级不高。
0 请登录后投票
   发表时间:2007-02-09  
我想用SPRING的DI很方便的,
0 请登录后投票
论坛首页 Java企业应用版

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