Struts2.1.6+Spring2.5.6+Hibernate3.3.1全注解實(shí)例詳解(二)
在上一章中詳細分析了JAR包的選擇,那么這次我將對例子中的一些必須的配置文件進(jìn)行下說(shuō)明。雖然這些配置在網(wǎng)上也很容易找到,但是很多都沒(méi)有講個(gè)因為所以出來(lái),這樣根本就得不到提高。在此,大象為各位詳細分析一下這些內容。
實(shí)例中涉及的配置文件有這么幾個(gè)
applicationContext.xml
jdbc.properties
log4j.properties
struts.xml
web.xml
我準備在本章中只講applicationContext.xml、jdbc.properties和web.xml。log4j的配置大同小異而且也不在本文范圍。至于struts.xml我準備留到后面與Action代碼一起來(lái)講,因為用的是struts2-convention-plugin插件來(lái)實(shí)現struts2的注解,所以這兩個(gè)結合起來(lái)講要好一些。
第二部分:分析配置文件
1、jdbc.properties
本例采用MySQL數據庫,所以我設置了一個(gè)屬性文件,用來(lái)存放一些連接信息和Hibernate相關(guān)的設置。
因為我們使用的是Hibernate來(lái)與數據庫進(jìn)行交互,把這些東西寫(xiě)在單獨的文件里,是方便修改,如果你想換成SQL Server或是Oracle,只需要更改driver、url以及dialect,而且還可以自由控制sql語(yǔ)句的顯示的開(kāi)關(guān),非常方便。至于寫(xiě)在這里怎么用呢?請接著(zhù)看下面的applicationContext.xml說(shuō)明。
2、applicationContext.xml
這個(gè)文件就是spring的主配置文件了,當然,本例也只有這么一個(gè)spring的配置文件,內容不多,但做的工作還是很多的,下面我給大家詳細分析一下。
我把這兩部分放在一起是因為這兩者是相互聯(lián)系的,而且也比較好說(shuō)明??梢赃@樣來(lái)理解,PropertyPlaceholderConfigurer這個(gè)類(lèi)就是讀取jdbc. properties文件,并將它們設置到這個(gè)類(lèi)的屬性中。然后再將下面數據源配置中定義的這些${jdbc.driver}、${jdbc.url}字符串換成屬性文件中相同名稱(chēng)的值。${}這種寫(xiě)法,是類(lèi)里面方法解析用的,網(wǎng)上都說(shuō)這是叫占位符,我看了源代碼的,其實(shí)是把它們當成字符串截取前后的特殊字符,再根據里面定義的名稱(chēng)找屬性文件中對應的值。所以這個(gè)類(lèi)只能讀取properties格式的文件,你如果還有其它需要加入的屬性文件,可以在list之間加入,寫(xiě)在value標簽里面。
根據base-package指定的路徑,掃描其下所有包含注解的Bean,并自動(dòng)注入。比如@Repository,@Service這些都是注解,前者表示持久層,后者表示業(yè)務(wù)層。這可是非常非常好的一個(gè)功能,是從Spring2.5開(kāi)始加入的一個(gè)非常棒的特性。有了它,我們將不用再去寫(xiě)那繁瑣的<bean id="" class="" />。本文的主旨就是全注解,就是為了告訴大家不用寫(xiě)配置文件(當然不是絕對不寫(xiě))來(lái)怎樣進(jìn)行開(kāi)發(fā)工作。關(guān)于這部分的具體情況,在后面代碼章節中會(huì )詳細講解。
這就是在Spring中定義Hibernate相關(guān)的配置,Spring已經(jīng)集成了這部分功能。通過(guò)class里面定義的類(lèi)名稱(chēng)我們很容易就能理解,這是使用注解的方式映射實(shí)體以及創(chuàng )建Hiberante SessionFactory。${hibernate.dialect}、${hibernate.show_sql}和上面的數據源配置獲取方式一樣,當applicationContext.xml定義好之后,就不用再對它進(jìn)行修改,而是將修改對象變成了jdbc.properties文件。
另外在Spring2.5.6版中,加入了一個(gè)很有用的小功能,就是packagesToScan屬性,它是根據value中定義的路徑來(lái)掃描其下所有的注解實(shí)體類(lèi)。大象對這個(gè)路徑做了多種測試,另外又看了源代碼,發(fā)現它只能匹配某一類(lèi)型的路徑,而不是所有路徑。比如上面的value值表示,掃描entity包下面的所有包中的注解類(lèi),如果你將類(lèi)直接放在entity包下,那么服務(wù)器啟動(dòng)和程序運行時(shí)都不會(huì )報錯,但是當你的代碼需要用到這個(gè)類(lèi)的時(shí)候,就會(huì )出現異常,提示你找不到實(shí)體。
這是事務(wù)定義,而且是使用注解方式定義事務(wù)(@Transactional),proxy-target-class="true"表示采用動(dòng)態(tài)代理類(lèi)來(lái)管理事務(wù),如果是false表示采用接口代理來(lái)管理事務(wù)(默認值為false)。什么意思呢?就是說(shuō)對于需要加入事務(wù)處理的類(lèi),如果是實(shí)現接口,那么將采用Spring的默認事務(wù)管理(Spring默認方式為接口),如果不采用接口,而直接使用類(lèi),那么就需要cglib類(lèi)庫的支持,它通過(guò)動(dòng)態(tài)的創(chuàng )建目標類(lèi)(就是你需要加入事務(wù)的類(lèi))的子類(lèi),然后對這子類(lèi)中的方法(當然是從目標類(lèi)中繼承來(lái)的)進(jìn)行事務(wù)管理。這其實(shí)就是AOP切面,而且從中可以看出來(lái),需要加入事務(wù)的方法不能為private、static、final 的方法。這樣說(shuō)也不是很?chē)栏?,說(shuō)它不能加入事務(wù),是說(shuō)它不能主動(dòng)的啟動(dòng)一個(gè)事務(wù),如果某個(gè)private方法是被某個(gè)public方法調用的,而public方法是可以被動(dòng)態(tài)代理加入事務(wù)的,所以這個(gè)private方法也一樣被加入了事務(wù),只是它處在public方法的事務(wù)之中。但是static和final這兩類(lèi)方法因為不能被子類(lèi)覆蓋,所以無(wú)法加入事務(wù)。如果這兩類(lèi)型的方法不被其它的事務(wù)方法所調用,那么它們就會(huì )以無(wú)事務(wù)的方式運行,因此很容易造成隱患,這一點(diǎn)請大家特別注意。

上面這個(gè)就是使用配置式來(lái)定義事務(wù),兩種方式的區別主要是,注解式只用寫(xiě)那么一句話(huà),然后在業(yè)務(wù)類(lèi)或方法中加入@Transactional這個(gè)注解標記,就完成事務(wù)聲明,不過(guò)對于每個(gè)業(yè)務(wù)類(lèi)都需要在類(lèi)或方法中加入這些標記。而配置式聲明,就是不用加這些標記,只要你的方法名稱(chēng)命名比較統一,就可以像上面這樣定義事務(wù)規范,然后在aop標簽中定義切入點(diǎn)與執行通知就行了。我感覺(jué)如果業(yè)務(wù)邏輯不是太復雜的情況,配置式會(huì )比較簡(jiǎn)單,而且修改起來(lái)也方便,這兩種方式我都寫(xiě)出來(lái)了,至于用哪一種,由你們自己決定。
3、web.xml
現在使用的Servlet容器還是2.4版,因此web.xml里面還是需要寫(xiě)配置文件的,到了3.0版就可以采取注解的方式來(lái)實(shí)現了。
Spring ApplicationContext配置文件的路徑,可使用通配符,applicationContext*.xml表示所有以applicationContext開(kāi)頭的xml文件。多個(gè)路徑用,號分隔。比如可以這樣寫(xiě):
不過(guò)推薦采用通配符的寫(xiě)法,能夠簡(jiǎn)單點(diǎn),為什么還要弄那么復雜呢?
context-param是在容器啟動(dòng)后最先被執行的,并且被放入到容器上下文中。在這里引入spring的配置文件,是供Spring的ContextLoaderListener監聽(tīng)器使用。而這個(gè)監聽(tīng)器中會(huì )有一個(gè)ContextLoade類(lèi)用來(lái)獲取這個(gè)配置文件中的信息。從而進(jìn)行Spring容器的初始化工作。因為是采用注解的方式來(lái)進(jìn)行開(kāi)發(fā),所以spring的配置文件其實(shí)只有一個(gè),上面那個(gè)星號可以去掉。
這個(gè)監聽(tīng)器就是為了讀取Spring的配置文件,這在上面已經(jīng)講到了。
這是Spring提供的一個(gè)用來(lái)防止內存泄漏的監聽(tīng)器。在我們使用struts2框架,或其它的某些類(lèi)庫時(shí),因為它們自身的設計,會(huì )用到Introspector(內?。C制來(lái)獲取Bean對象的信息。但不幸的是,這些框架或類(lèi)庫在分析完一個(gè)類(lèi)之后卻沒(méi)有將它從內存中清除掉,內存中還保留有大量的靜態(tài)資源,而這些東西又無(wú)法進(jìn)行垃圾回收,因此產(chǎn)生了很?chē)乐氐膬却嫘孤﹩?wèn)題。直接表現為服務(wù)器的內存使用會(huì )隨著(zhù)時(shí)間而不斷上升,最后的結果當然就是服務(wù)器當掉。所以在這里加入此監聽(tīng)器,能夠幫助我們更好的處理內存資源回收的問(wèn)題。
這是Spring的編碼過(guò)濾器,我們可以直接拿來(lái)用,相信這段配置應該很好理解,不過(guò)請大家注意forceEncoding這個(gè)參數,把它設置為true表示不管請求中的編碼是什么格式,都將強制采用encoding中設置的編碼方式。另外對于響應也將按照encoding指定的編碼進(jìn)行設置。另外不建議將編碼設置成gb2312或是gbk格式,請采用基于Unicode的UTF-8編碼。
這個(gè)過(guò)濾器是個(gè)好東西,有了它,我們在使用Hibernate延遲加載的時(shí)候,就不會(huì )再為因Session被關(guān)閉,導致延遲加載數據異常而頭痛了。網(wǎng)上有很多人說(shuō)這個(gè)不好,其實(shí)在使用中,效果還是不錯的。
首先我要說(shuō)這個(gè)過(guò)濾器的名字很雷,不知道寫(xiě)這類(lèi)的家伙是不是個(gè)變態(tài),或者喜歡惡搞。主要原因就是,這個(gè)過(guò)濾器的功能是推遲清理值棧中的值,以便在web層中進(jìn)行訪(fǎng)問(wèn),另外就是為了配合SiteMesh裝飾器進(jìn)行工作(官方中的說(shuō)明)。如果不加這個(gè),那么Struts2的默認過(guò)濾器就會(huì )清空值棧中的值,這樣就會(huì )導致異常。所以說(shuō)這類(lèi)的名字和功能完全不搭邊,很容易讓人產(chǎn)生誤解。
在2.1.6版本里面,已經(jīng)用這個(gè)過(guò)濾器取代了以前的FilterDispatcher,而且在api文檔中已經(jīng)標注為@deprecated(不贊成),并說(shuō)明是從Struts 2.1.3版開(kāi)始就棄用這個(gè)過(guò)濾器了,改用StrutsPrepareAndExecuteFilter,除此之外,還可以選擇StrutsPrepareFilter和StrutsExecuteFilter。不過(guò)大象建議大家還是選擇StrutsPrepareAndExecuteFilter吧,這也是官方推薦的。
web.xml里面的幾個(gè)重要的配置就這些,不過(guò)不要忘了,給這些filter加上filter-mapping映射。還有一點(diǎn),請注意這些過(guò)濾器的順序,這個(gè)順序是很重要的,程序運行時(shí),是根據這些filter-mapping的排列順序依次執行過(guò)濾操作的。如果不想出現莫名其妙的錯誤,請控制好這些過(guò)濾器映射的順序。
我會(huì )在最后一章附上源碼,大家就這樣慢慢看吧??吹阶詈笠徽碌臅r(shí)候,可能這些相關(guān)的知識就比較清楚了。到時(shí)再對照源碼練習下,應該會(huì )有一些收獲。恩,這部分就到此結束了,我們下次繼續。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。