欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
使用 Hibernate 和 Spring AOP 構建泛型類(lèi)型安全的 DAO

對于大多數開(kāi)發(fā)人員,為系統中的每個(gè) DAO 編寫(xiě)幾乎相同的代碼到目前為止已經(jīng)成為一種習慣。雖然所有人都將這種重復標識為 “代碼味道”,但我們大多數都已經(jīng)學(xué)會(huì )忍受它。其實(shí)有解決方案??梢允褂迷S多 ORM 工具來(lái)避免代碼重復。例如,使用 Hibernate,您可以簡(jiǎn)單地為所有的持久域對象直接使用會(huì )話(huà)操作。這種方法的缺點(diǎn)是損失了類(lèi)型安全。

為什么您要為數據訪(fǎng)問(wèn)代碼提供類(lèi)型安全接口?我會(huì )爭辯說(shuō),當它與現代 IDE 工具一起使用時(shí),會(huì )減少編程錯誤并提高生產(chǎn)率。首先,類(lèi)型安全接口清楚地指明哪些域對象具有可用的持久存儲。其次,它消除了易出錯的類(lèi)型強制轉換的需要(這是一個(gè)在查詢(xún)操作中比在 CRUD 中更常見(jiàn)的問(wèn)題)。最后,它有效利用了今天大多數 IDE 具備的自動(dòng)完成特性。使用自動(dòng)完成是記住什么查詢(xún)可用于特定域類(lèi)的快捷方法。

在本文中,我將為您展示如何避免再三地重復 DAO 代碼,而仍保留類(lèi)型安全接口的優(yōu)點(diǎn)。事實(shí)上,您需要為每個(gè)新 DAO 編寫(xiě)的只是 Hibernate 映射文件、無(wú)格式舊 Java 接口以及 Spring 配置文件中的 10 行。

DAO 實(shí)現

DAO 模式對任何企業(yè) Java 開(kāi)發(fā)人員來(lái)說(shuō)都應該很熟悉。但是模式的實(shí)現各不相同,所以我們來(lái)澄清一下本文提供的 DAO 實(shí)現背后的假設:

  • 系統中的所有數據庫訪(fǎng)問(wèn)都通過(guò) DAO 進(jìn)行以實(shí)現封裝。
  • 每個(gè) DAO 實(shí)例負責一個(gè)主要域對象或實(shí)體。如果域對象具有獨立生命周期,它應具有自己的 DAO。
  • DAO 負責域對象的創(chuàng )建、讀?。ò粗麈I)、更新和刪除(creations, reads, updates, and deletions,CRUD)。
  • DAO 可允許基于除主鍵之外的標準進(jìn)行查詢(xún)。我將之稱(chēng)為查找器方法查找器。查找器的返回值通常是 DAO 負責的域對象集合。
  • DAO 不負責處理事務(wù)、會(huì )話(huà)或連接。這些不由 DAO 處理是為了實(shí)現靈活性。

泛型 DAO 接口

泛型 DAO 的基礎是其 CRUD 操作。下面的接口定義泛型 DAO 的方法:


清單 1. 泛型 DAO 接口

public interface GenericDao <T, PK extends Serializable> {            /** Persist the newInstance object into database */            PK create(T newInstance);            /** Retrieve an object that was previously persisted to the database using            *   the indicated id as primary key            */            T read(PK id);            /** Save changes made to a persistent object.  */            void update(T transientObject);            /** Remove an object from persistent storage in the database */            void delete(T persistentObject);            }            

實(shí)現接口

用 Hibernate 實(shí)現清單 1 中的接口十分簡(jiǎn)單,如清單 2 所示。它只需調用底層 Hibernate 方法和添加強制類(lèi)型轉換。Spring 負責會(huì )話(huà)和事務(wù)管理。(當然,我假設這些函數已做了適當的設置,但該主題在 Hibernate 和 Springt 手冊中有詳細介紹。)


清單 2. 第一個(gè)泛型 DAO 實(shí)現

public class GenericDaoHibernateImpl <T, PK extends Serializable>            implements GenericDao<T, PK>, FinderExecutor {            private Class<T> type;            public GenericDaoHibernateImpl(Class<T> type) {            this.type = type;            }            public PK create(T o) {            return (PK) getSession().save(o);            }            public T read(PK id) {            return (T) getSession().get(type, id);            }            public void update(T o) {            getSession().update(o);            }            public void delete(T o) {            getSession().delete(o);            }            // Not showing implementations of getSession() and setSessionFactory()            }            

Spring 配置

最后,在 Spring 配置中,我創(chuàng )建了 GenericDaoHibernateImpl 的一個(gè)實(shí)例。必須告訴 GenericDaoHibernateImpl 的構造函數 DAO 實(shí)例將負責哪個(gè)域類(lèi)。只有這樣,Hibernate 才能在運行時(shí)知道由 DAO 管理的對象類(lèi)型。在清單 3 中,我將域類(lèi) Person 從示例應用程序傳遞給構造函數,并將先前配置的 Hibernate 會(huì )話(huà)工廠(chǎng)設置為已實(shí)例化的 DAO 的參數:


清單 3. 配置 DAO

<bean id="personDao" class="genericdao.impl.GenericDaoHibernateImpl">            <constructor-arg>            <value>genericdaotest.domain.Person</value>            </constructor-arg>            <property name="sessionFactory">            <ref bean="sessionFactory"/>            </property>            </bean>            

可用的泛型 DAO

我還沒(méi)有完成,但我所完成的確實(shí)已經(jīng)可以使用了。在清單 4 中,可以看到原封不動(dòng)使用該泛型 DAO 的示例:


清單 4. 使用 DAO

public void someMethodCreatingAPerson() {            ...            GenericDao dao = (GenericDao)            beanFactory.getBean("personDao"); // This should normally be injected            Person p = new Person("Per", 90);            dao.create(p);            }            

現在,我有一個(gè)能夠進(jìn)行類(lèi)型安全 CRUD 操作的泛型 DAO。讓子類(lèi) GenericDaoHibernateImpl 為每個(gè)域對象添加查詢(xún)能力將非常合理。因為本文的目的在于展示如何不為每個(gè)查詢(xún)編寫(xiě)顯式的 Java 代碼來(lái)實(shí)現查詢(xún),但是,我將使用其他兩個(gè)工具將查詢(xún)引入 DAO,也就是 Spring AOP 和 Hibernate 命名的查詢(xún)。

Spring AOP introductions

可以使用 Spring AOP 中的 introductions 將功能添加到現有對象,方法是將功能包裝在代理中,定義應實(shí)現的接口,并將所有先前未支持的方法指派到單個(gè)處理程序。在我的 DAO 實(shí)現中,我使用 introductions 將許多查找器方法添加到現有泛型 DAO 類(lèi)中。因為查找器方法是特定于每個(gè)域對象的,因此將其應用于泛型 DAO 的類(lèi)型化接口。

Spring 配置如清單 5 所示:


清單 5. FinderIntroductionAdvisor 的 Spring 配置

<bean id="finderIntroductionAdvisor" 
class="genericdao.impl.FinderIntroductionAdvisor"/> <bean id="abstractDaoTarget" class="genericdao.impl.GenericDaoHibernateImpl" abstract="true"> <property name="sessionFactory"> <ref bean="sessionFactory"/> </property> </bean> <bean id="abstractDao" class="org.springframework.aop.framework.ProxyFactoryBean" abstract="true"> <property name="interceptorNames"> <list> <value>finderIntroductionAdvisor</value> </list> </property> </bean>

在清單 5 的配置文件中,我定義了三個(gè) Spring bean。第一個(gè) bean 是 FinderIntroductionAdvisor,它處理引入到 DAO 的所有方法,這些方法在 GenericDaoHibernateImpl 類(lèi)中不可用。我稍后將詳細介紹 Advisor bean。

第二個(gè) bean 是 “抽象的”。在 Spring 中,這意味著(zhù)該 bean 可在其他 bean 定義中被重用,但不被實(shí)例化。除了抽象特性之外,該 bean 定義只指出我想要 GenericDaoHibernateImpl 的實(shí)例以及該實(shí)例需要對 SessionFactory 的引用。注意,GenericDaoHibernateImpl 類(lèi)僅定義一個(gè)構造函數,該構造函數接受域類(lèi)作為其參數。因為該 bean 定義是抽象的,所以我將來(lái)可以無(wú)數次地重用該定義,并將構造函數參數設置為合適的域類(lèi)。

最后,第三個(gè)也是最有趣的 bean 將 GenericDaoHibernateImpl 的 vanilla 實(shí)例包裝在代理中,賦予其執行查找器方法的能力。該 bean 定義也是抽象的,不指定希望引入到 vanilla DAO 的接口。該接口對于每個(gè)具體的實(shí)例是不同的。注意,清單 5 顯示的整個(gè)配置僅定義一次。

擴展 GenericDAO

當然,每個(gè) DAO 的接口都基于 GenericDao 接口。我只需使該接口適應特定的域類(lèi)并擴展該接口以包括查找器方法。在清單 6 中,可以看到為特定目的擴展的 GenericDao 接口示例:


清單 6. PersonDao 接口

public interface PersonDao extends GenericDao<Person, Long> {            List<Person> findByName(String name);            }            

很明顯,清單 6 中定義的方法旨在按名稱(chēng)查找 Person。必需的 Java 實(shí)現代碼全部是泛型代碼,在添加更多 DAO 時(shí)不需要任何更新。

配置 PersonDao

因為 Spring 配置依賴(lài)于先前定義的 “抽象” bean,因此它變得相當簡(jiǎn)潔。我需要指出 DAO 負責哪個(gè)域類(lèi),并且需要告訴 Springs 該 DAO 應實(shí)現哪個(gè)接口(一些方法是直接使用,一些方法則是通過(guò)使用 introductions 來(lái)使用)。清單 7 展示了 PersonDAO 的 Spring 配置文件:


清單 7. PersonDao 的 Spring 配置

<bean id="personDao" parent="abstractDao">            <property name="proxyInterfaces">            <value>genericdaotest.dao.PersonDao</value>            </property>            <property name="target">            <bean parent="abstractDaoTarget">            <constructor-arg>            <value>genericdaotest.domain.Person</value>            </constructor-arg>            </bean>            </property>            </bean>            

在清單 8 中,可以看到使用了這個(gè)更新后的 DAO 版本:


清單 8. 使用類(lèi)型安全接口

public void someMethodCreatingAPerson() {            ...            PersonDao dao = (PersonDao)            beanFactory.getBean("personDao"); // This should normally be injected            Person p = new Person("Per", 90);            dao.create(p);            List<Person> result = dao.findByName("Per"); // Runtime exception            }            

雖然清單 8 中的代碼是使用類(lèi)型安全 PersonDao 接口的正確方法,但 DAO 的實(shí)現并不完整。調用 findByName() 會(huì )導致運行時(shí)異常。問(wèn)題在于我還沒(méi)有實(shí)現調用 findByName() 所必需的查詢(xún)。剩下要做的就是指定查詢(xún)。為更正該問(wèn)題,我使用了 Hibernate 命名查詢(xún)。

Hibernate 命名查詢(xún)

使用 Hibernate,可以在 Hibernate 映射文件 (hbm.xml) 中定義 HQL 查詢(xún)并為其命名。稍后可以通過(guò)簡(jiǎn)單地引用給定名稱(chēng)來(lái)在 Java 代碼中使用該查詢(xún)。該方法的優(yōu)點(diǎn)之一是能夠在部署時(shí)優(yōu)化查詢(xún),而無(wú)需更改代碼。您一會(huì )將會(huì )看到,另一個(gè)優(yōu)點(diǎn)是無(wú)需編寫(xiě)任何新 Java 實(shí)現代碼,就可以實(shí)現 “完整的” DAO。清單 9 是帶有命名查詢(xún)的映射文件的示例:


清單 9. 帶有命名查詢(xún)的映射文件

 <hibernate-mapping package="genericdaotest.domain">            <class name="Person">            <id name="id">            <generator class="native"/>            </id>            <property name="name" />            <property name="weight" />            </class>            <query name="Person.findByName">            <![CDATA[select p from Person p where p.name = ? ]]>            </query>            </hibernate-mapping>            

清單 9 定義了域類(lèi) Person 的 Hibernate 映射,該域類(lèi)具有兩個(gè)屬性:nameweight。Person 是具有上述屬性的簡(jiǎn)單 POJO。該文件還包含一個(gè)在數據庫中查找 Person 所有實(shí)例的查詢(xún),其中 “name” 等于提供的參數。Hibernate 不為命名查詢(xún)提供任何真正的名稱(chēng)空間功能。出于討論目的,我為所有查詢(xún)名稱(chēng)都加了域類(lèi)的短(非限定)名稱(chēng)作為前綴。在現實(shí)世界中,使用包括包名稱(chēng)的完全類(lèi)名可能是更好的主意。

逐步概述

您已經(jīng)看到了為任何域對象創(chuàng )建和配置新 DAO 所必需的全部步驟。三個(gè)簡(jiǎn)單的步驟是:

  1. 定義一個(gè)接口,它擴展 GenericDao 并包含所需的任何查找器方法。
  2. 將每個(gè)查找器的命名查詢(xún)添加到域對象的 hbm.xml 映射文件。
  3. 為 DAO 添加 10 行 Spring 配置文件。

查看執行查找器方法的代碼(只編寫(xiě)了一次?。﹣?lái)結束我的討論。

可重用的 DAO 類(lèi)

使用的 Spring advisor 和 interceptor 很簡(jiǎn)單,事實(shí)上它們的工作是向后引用 GenericDaoHibernateImplClass。方法名以 “find” 打頭的所有調用都傳遞給 DAO 和單個(gè)方法 executeFinder()。


清單 10. FinderIntroductionAdvisor 的實(shí)現

public class FinderIntroductionAdvisor extends DefaultIntroductionAdvisor {            public FinderIntroductionAdvisor() {            super(new FinderIntroductionInterceptor());            }            }            public class FinderIntroductionInterceptor implements IntroductionInterceptor {            public Object invoke(MethodInvocation methodInvocation) throws Throwable {            FinderExecutor genericDao = (FinderExecutor) methodInvocation.getThis();            String methodName = methodInvocation.getMethod().getName();            if (methodName.startsWith("find")) {            Object[] arguments = methodInvocation.getArguments();            return genericDao.executeFinder(methodInvocation.getMethod(), arguments);            } else {            return methodInvocation.proceed();            }            }            public boolean implementsInterface(Class intf) {            return intf.isInterface() && FinderExecutor.class.isAssignableFrom(intf);            }            }            

executeFinder() 方法

清單 10 的實(shí)現中惟一缺少的是 executeFinder() 實(shí)現。該代碼查看調用的類(lèi)和方法的名稱(chēng),并使用配置上的約定將其與 Hibernate 查詢(xún)的名稱(chēng)相匹配。還可以使用 FinderNamingStrategy 來(lái)支持其他命名查詢(xún)的方法。默認實(shí)現查找叫做 “ClassName.methodName” 的查詢(xún),其中 ClassName 是不帶包的短名稱(chēng)。清單 11 完成了泛型類(lèi)型安全 DAO 實(shí)現:


清單 11. executeFinder() 的實(shí)現

public List<T> executeFinder(Method method, final Object[] queryArgs) {            final String queryName = queryNameFromMethod(method);            final Query namedQuery = getSession().getNamedQuery(queryName);            String[] namedParameters = namedQuery.getNamedParameters();            for(int i = 0; i < queryArgs.length; i++) {            Object arg = queryArgs[i];            Type argType =  namedQuery.setParameter(i, arg);            }            return (List<T>) namedQuery.list();            }            public String queryNameFromMethod(Method finderMethod) {            return type.getSimpleName() + "." + finderMethod.getName();            }            

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Struts+Spring+Hibernate的技術(shù)實(shí)現
當 Hibernate 遇上 Spring
使用struts+spring+hibernate 組裝web應用
使用AOP實(shí)現類(lèi)型安全的泛型DAO - 東方未名 - BlogJava
重構項目使用Spring+Hibernate+HibernateAnnotation+GenericDao技術(shù)
Spring 系列: Spring 框架簡(jiǎn)介
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久