﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-csuct</title><link>http://www.blogjava.net/csuct/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 07 May 2026 04:29:27 GMT</lastBuildDate><pubDate>Thu, 07 May 2026 04:29:27 GMT</pubDate><ttl>60</ttl><item><title>泛型dao 详细剖析</title><link>http://www.blogjava.net/csuct/archive/2010/03/26/316609.html</link><dc:creator>csuct</dc:creator><author>csuct</author><pubDate>Thu, 25 Mar 2010 16:13:00 GMT</pubDate><guid>http://www.blogjava.net/csuct/archive/2010/03/26/316609.html</guid><wfw:comment>http://www.blogjava.net/csuct/comments/316609.html</wfw:comment><comments>http://www.blogjava.net/csuct/archive/2010/03/26/316609.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/csuct/comments/commentRss/316609.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/csuct/services/trackbacks/316609.html</trackback:ping><description><![CDATA[<p>对于大多数开发人员，为系统中的每个 DAO 编写几乎相同的代码到目前为止已经成为一种习惯。虽然所有人都将这种重复标识为 &#8220;代码味道&#8221;，但我们大多数都已经学会忍受它。其实有解决方案。可以使用许多 ORM 工具来避免代码重复。例如，使用 Hibernate，您可以简单地为所有的持久域对象直接使用会话操作。这种方法的缺点是损失了类型安全。</p>
<p>为什么您要为数据访问代码提供类型安全接口？我会争辩说，当它与现代 IDE 工具一起使用时，会减少编程错误并提高生产率。首先，类型安全接口清楚地指明哪些域对象具有可用的持久存储。其次，它消除了易出错的类型强制转换的需要（这是一个在查询操作中比在 CRUD 中更常见的问题）。最后，它有效利用了今天大多数 IDE 具备的自动完成特性。使用自动完成是记住什么查询可用于特定域类的快捷方法。</p>
<p>在本文中，我将为您展示如何避免再三地重复 DAO 代码，而仍保留类型安全接口的优点。事实上，您需要为每个新 DAO 编写的只是 Hibernate 映射文件、无格式旧 Java 接口以及 Spring 配置文件中的 10 行。</p>
<p>DAO 实现</p>
<p>DAO 模式对任何企业 Java 开发人员来说都应该很熟悉。但是模式的实现各不相同，所以我们来澄清一下本文提供的 DAO 实现背后的假设：</p>
<p>系统中的所有数据库访问都通过 DAO 进行以实现封装。 <br />
每个 DAO 实例负责一个主要域对象或实体。如果域对象具有独立生命周期，它应具有自己的 DAO。 <br />
DAO 负责域对象的创建、读取（按主键）、更新和删除（creations, reads, updates, and deletions，CRUD）。 <br />
DAO 可允许基于除主键之外的标准进行查询。我将之称为查找器方法 或查找器。查找器的返回值通常是 DAO 负责的域对象集合。 <br />
DAO 不负责处理事务、会话或连接。这些不由 DAO 处理是为了实现灵活性。 </p>
<p>&nbsp;</p>
<p>泛型 DAO 接口</p>
<p>泛型 DAO 的基础是其 CRUD 操作。下面的接口定义泛型 DAO 的方法：</p>
<p><br />
清单 1. 泛型 DAO 接口<br />
public interface GenericDao &lt;T, PK extends Serializable&gt; {</p>
<p>&nbsp;&nbsp;&nbsp; /** Persist the newInstance object into database */<br />
&nbsp;&nbsp;&nbsp; PK create(T newInstance);</p>
<p>&nbsp;&nbsp;&nbsp; /** Retrieve an object that was previously persisted to the database using<br />
&nbsp;&nbsp;&nbsp;&nbsp; *&nbsp;&nbsp; the indicated id as primary key<br />
&nbsp;&nbsp;&nbsp;&nbsp; */<br />
&nbsp;&nbsp;&nbsp; T read(PK id);</p>
<p>&nbsp;&nbsp;&nbsp; /** Save changes made to a persistent object.&nbsp; */<br />
&nbsp;&nbsp;&nbsp; void update(T transientObject);</p>
<p>&nbsp;&nbsp;&nbsp; /** Remove an object from persistent storage in the database */<br />
&nbsp;&nbsp;&nbsp; void delete(T persistentObject);<br />
}</p>
<p>&nbsp;</p>
<p><br />
实现接口</p>
<p>用 Hibernate 实现清单 1 中的接口十分简单，如清单 2 所示。它只需调用底层 Hibernate 方法和添加强制类型转换。Spring 负责会话和事务管理。（当然，我假设这些函数已做了适当的设置，但该主题在 Hibernate 和 Springt 手册中有详细介绍。）</p>
<p><br />
清单 2. 第一个泛型 DAO 实现<br />
public class GenericDaoHibernateImpl &lt;T, PK extends Serializable&gt;<br />
&nbsp;&nbsp;&nbsp; implements GenericDao&lt;T, PK&gt;, FinderExecutor {<br />
&nbsp;&nbsp;&nbsp; private Class&lt;T&gt; type;</p>
<p>&nbsp;&nbsp;&nbsp; public GenericDaoHibernateImpl(Class&lt;T&gt; type) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.type = type;<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public PK create(T o) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (PK) getSession().save(o);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public T read(PK id) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (T) getSession().get(type, id);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public void update(T o) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getSession().update(o);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public void delete(T o) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; getSession().delete(o);<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; // Not showing implementations of getSession() and setSessionFactory()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;</p>
<p><br />
Spring 配置</p>
<p>最后，在 Spring 配置中，我创建了 GenericDaoHibernateImpl 的一个实例。必须告诉 GenericDaoHibernateImpl 的构造函数 DAO 实例将负责哪个域类。只有这样，Hibernate 才能在运行时知道由 DAO 管理的对象类型。在清单 3 中，我将域类 Person 从示例应用程序传递给构造函数，并将先前配置的 Hibernate 会话工厂设置为已实例化的 DAO 的参数：</p>
<p><br />
清单 3. 配置 DAO<br />
&lt;bean id="personDao" class="genericdao.impl.GenericDaoHibernateImpl"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;constructor-arg&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;genericdaotest.domain.Person&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/constructor-arg&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="sessionFactory"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref bean="sessionFactory"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;</p>
<p><br />
可用的泛型 DAO</p>
<p>我还没有完成，但我所完成的确实已经可以使用了。在清单 4 中，可以看到原封不动使用该泛型 DAO 的示例：</p>
<p><br />
清单 4. 使用 DAO<br />
public void someMethodCreatingAPerson() {<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; GenericDao dao = (GenericDao)<br />
&nbsp;&nbsp;&nbsp;&nbsp; beanFactory.getBean("personDao"); // This should normally be injected</p>
<p>&nbsp;&nbsp;&nbsp; Person p = new Person("Per", 90);<br />
&nbsp;&nbsp;&nbsp; dao.create(p);<br />
}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p><br />
现在，我有一个能够进行类型安全 CRUD 操作的泛型 DAO。让子类 GenericDaoHibernateImpl 为每个域对象添加查询能力将非常合理。因为本文的目的在于展示如何不为每个查询编写显式的 Java 代码来实现查询，但是，我将使用其他两个工具将查询引入 DAO，也就是 Spring AOP 和 Hibernate 命名的查询。</p>
<p>&nbsp;</p>
<p><br />
Spring AOP introductions</p>
<p>可以使用 Spring AOP 中的 introductions 将功能添加到现有对象，方法是将功能包装在代理中，定义应实现的接口，并将所有先前未支持的方法指派到单个处理程序。在我的 DAO 实现中，我使用 introductions 将许多查找器方法添加到现有泛型 DAO 类中。因为查找器方法是特定于每个域对象的，因此将其应用于泛型 DAO 的类型化接口。</p>
<p>Spring 配置如清单 5 所示：</p>
<p><br />
清单 5. FinderIntroductionAdvisor 的 Spring 配置<br />
&lt;bean id="finderIntroductionAdvisor" class="genericdao.impl.FinderIntroductionAdvisor"/&gt;</p>
<p>&lt;bean id="abstractDaoTarget"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="genericdao.impl.GenericDaoHibernateImpl" abstract="true"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="sessionFactory"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;ref bean="sessionFactory"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&lt;/bean&gt;</p>
<p>&lt;bean id="abstractDao"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="interceptorNames"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;finderIntroductionAdvisor&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/list&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p><br />
在清单 5 的配置文件中，我定义了三个 Spring bean。第一个 bean 是 FinderIntroductionAdvisor，它处理引入到 DAO 的所有方法，这些方法在 GenericDaoHibernateImpl 类中不可用。我稍后将详细介绍 Advisor bean。</p>
<p>第二个 bean 是 &#8220;抽象的&#8221;。在 Spring 中，这意味着该 bean 可在其他 bean 定义中被重用，但不被实例化。除了抽象特性之外，该 bean 定义只指出我想要 GenericDaoHibernateImpl 的实例以及该实例需要对 SessionFactory 的引用。注意，GenericDaoHibernateImpl 类仅定义一个构造函数，该构造函数接受域类作为其参数。因为该 bean 定义是抽象的，所以我将来可以无数次地重用该定义，并将构造函数参数设置为合适的域类。</p>
<p>最后，第三个也是最有趣的 bean 将 GenericDaoHibernateImpl 的 vanilla 实例包装在代理中，赋予其执行查找器方法的能力。该 bean 定义也是抽象的，不指定希望引入到 vanilla DAO 的接口。该接口对于每个具体的实例是不同的。注意，清单 5 显示的整个配置仅定义一次。</p>
<p>&nbsp;</p>
<p>扩展 GenericDAO</p>
<p>当然，每个 DAO 的接口都基于 GenericDao 接口。我只需使该接口适应特定的域类并扩展该接口以包括查找器方法。在清单 6 中，可以看到为特定目的扩展的 GenericDao 接口示例：</p>
<p><br />
清单 6. PersonDao 接口<br />
public interface PersonDao extends GenericDao&lt;Person, Long&gt; {<br />
&nbsp;&nbsp;&nbsp; List&lt;Person&gt; findByName(String name);<br />
}</p>
<p>&nbsp;</p>
<p><br />
很明显，清单 6 中定义的方法旨在按名称查找 Person。必需的 Java 实现代码全部是泛型代码，在添加更多 DAO 时不需要任何更新。</p>
<p>配置 PersonDao</p>
<p>因为 Spring 配置依赖于先前定义的 &#8220;抽象&#8221; bean，因此它变得相当简洁。我需要指出 DAO 负责哪个域类，并且需要告诉 Springs 该 DAO 应实现哪个接口（一些方法是直接使用，一些方法则是通过使用 introductions 来使用）。清单 7 展示了 PersonDAO 的 Spring 配置文件：</p>
<p><br />
清单 7. PersonDao 的 Spring 配置<br />
&lt;bean id="personDao" parent="abstractDao"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;property name="proxyInterfaces"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;genericdaotest.dao.PersonDao&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;property name="target"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean parent="abstractDaoTarget"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;constructor-arg&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;genericdaotest.domain.Person&lt;/value&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/constructor-arg&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br />
&lt;/bean&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p><br />
在清单 8 中，可以看到使用了这个更新后的 DAO 版本：</p>
<p><br />
清单 8. 使用类型安全接口<br />
public void someMethodCreatingAPerson() {<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; PersonDao dao = (PersonDao)<br />
&nbsp;&nbsp;&nbsp;&nbsp; beanFactory.getBean("personDao"); // This should normally be injected</p>
<p>&nbsp;&nbsp;&nbsp; Person p = new Person("Per", 90);<br />
&nbsp;&nbsp;&nbsp; dao.create(p);</p>
<p>&nbsp;&nbsp;&nbsp; List&lt;Person&gt; result = dao.findByName("Per"); // Runtime exception<br />
}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p><br />
虽然清单 8 中的代码是使用类型安全 PersonDao 接口的正确方法，但 DAO 的实现并不完整。调用 findByName() 会导致运行时异常。问题在于我还没有实现调用 findByName() 所必需的查询。剩下要做的就是指定查询。为更正该问题，我使用了 Hibernate 命名查询。</p>
<p>&nbsp;</p>
<p>Hibernate 命名查询</p>
<p>使用 Hibernate，可以在 Hibernate 映射文件 (hbm.xml) 中定义 HQL 查询并为其命名。稍后可以通过简单地引用给定名称来在 Java 代码中使用该查询。该方法的优点之一是能够在部署时优化查询，而无需更改代码。您一会将会看到，另一个优点是无需编写任何新 Java 实现代码，就可以实现 &#8220;完整的&#8221; DAO。清单 9 是带有命名查询的映射文件的示例：</p>
<p><br />
清单 9. 带有命名查询的映射文件<br />
&nbsp;&lt;hibernate-mapping package="genericdaotest.domain"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;class name="Person"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;id name="id"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator class="native"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="name" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="weight" /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/class&gt;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; &lt;query name="Person.findByName"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;![CDATA[select p from Person p where p.name = ? ]]&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;/query&gt;<br />
&nbsp;&lt;/hibernate-mapping&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p><br />
清单 9 定义了域类 Person 的 Hibernate 映射，该域类具有两个属性：name 和 weight。Person 是具有上述属性的简单 POJO。该文件还包含一个在数据库中查找 Person 所有实例的查询，其中 &#8220;name&#8221; 等于提供的参数。Hibernate 不为命名查询提供任何真正的名称空间功能。出于讨论目的，我为所有查询名称都加了域类的短（非限定）名称作为前缀。在现实世界中，使用包括包名称的完全类名可能是更好的主意。</p>
<p><br />
逐步概述</p>
<p>您已经看到了为任何域对象创建和配置新 DAO 所必需的全部步骤。三个简单的步骤是：</p>
<p>定义一个接口，它扩展 GenericDao 并包含所需的任何查找器方法。 <br />
将每个查找器的命名查询添加到域对象的 hbm.xml 映射文件。 <br />
为 DAO 添加 10 行 Spring 配置文件。 <br />
查看执行查找器方法的代码（只编写了一次！）来结束我的讨论。</p>
<p><br />
可重用的 DAO 类</p>
<p>使用的 Spring advisor 和 interceptor 很简单，事实上它们的工作是向后引用 GenericDaoHibernateImplClass。方法名以 &#8220;find&#8221; 打头的所有调用都传递给 DAO 和单个方法 executeFinder()。</p>
<p><br />
清单 10. FinderIntroductionAdvisor 的实现<br />
public class FinderIntroductionAdvisor extends DefaultIntroductionAdvisor {<br />
&nbsp;&nbsp;&nbsp; public FinderIntroductionAdvisor() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super(new FinderIntroductionInterceptor());<br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p>public class FinderIntroductionInterceptor implements IntroductionInterceptor {</p>
<p>&nbsp;&nbsp;&nbsp; public Object invoke(MethodInvocation methodInvocation) throws Throwable {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FinderExecutor genericDao = (FinderExecutor) methodInvocation.getThis();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String methodName = methodInvocation.getMethod().getName();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (methodName.startsWith("find")) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object[] arguments = methodInvocation.getArguments();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return genericDao.executeFinder(methodInvocation.getMethod(), arguments);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return methodInvocation.proceed();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; public boolean implementsInterface(Class intf) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return intf.isInterface() &amp;&amp; FinderExecutor.class.isAssignableFrom(intf);<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
&nbsp;</p>
<p><br />
executeFinder() 方法</p>
<p>清单 10 的实现中惟一缺少的是 executeFinder() 实现。该代码查看调用的类和方法的名称，并使用配置上的约定将其与 Hibernate 查询的名称相匹配。还可以使用 FinderNamingStrategy 来支持其他命名查询的方法。默认实现查找叫做 &#8220;ClassName.methodName&#8221; 的查询，其中 ClassName 是不带包的短名称。清单 11 完成了泛型类型安全 DAO 实现： </p>
<p><br />
清单 11. executeFinder() 的实现<br />
public List&lt;T&gt; executeFinder(Method method, final Object[] queryArgs) {<br />
&nbsp;&nbsp;&nbsp;&nbsp; final String queryName = queryNameFromMethod(method);<br />
&nbsp;&nbsp;&nbsp;&nbsp; final Query namedQuery = getSession().getNamedQuery(queryName);<br />
&nbsp;&nbsp;&nbsp;&nbsp; String[] namedParameters = namedQuery.getNamedParameters();<br />
&nbsp;&nbsp;&nbsp;&nbsp; for(int i = 0; i &lt; queryArgs.length; i++) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Object arg = queryArgs[i];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Type argType =&nbsp; namedQuery.setParameter(i, arg);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (List&lt;T&gt;) namedQuery.list();<br />
&nbsp;}</p>
<p>&nbsp;public String queryNameFromMethod(Method finderMethod) {<br />
&nbsp;&nbsp;&nbsp;&nbsp; return type.getSimpleName() + "." + finderMethod.getName();<br />
&nbsp;}<br />
&nbsp;</p>
<p>&nbsp;</p>
<p>结束语</p>
<p>在 Java 5 之前，该语言不支持编写既类型安全又 泛型的代码，您必须只能选择其中之一。在本文中，您已经看到一个结合使用 Java 5 泛型与 Spring 和 Hibernate（以及 AOP）等工具来提高生产率的示例。泛型类型安全 DAO 类相当容易编写 —— 您只需要单个接口、一些命名查询和为 Spring 配置添加的 10 行代码 —— 而且可以极大地减少错误并节省时间。</p>
<p>几乎本文的所有代码都是可重用的。尽管您的 DAO 类可能包含此处没有实现的查询和操作类型（比如，批操作），但使用我所展示的技术，您至少应该能够实现其中的一部分。参阅 参考资料 了解其他泛型类型安全 DAO 类实现。</p>
<p>&nbsp;</p>
<p>本文来自CSDN博客：http://blog.csdn.net/jhaij/archive/2007/06/17/1655535.aspx</p>
<img src ="http://www.blogjava.net/csuct/aggbug/316609.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/csuct/" target="_blank">csuct</a> 2010-03-26 00:13 <a href="http://www.blogjava.net/csuct/archive/2010/03/26/316609.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>