????但Spring MVC+hibernate的Sample如Appfuse的代碼卻算不得最簡潔優(yōu)美好讀,如果在自己的項目中繼續(xù)發(fā)揮我們最擅長的依樣畫葫蘆大法,美好愿望未必會實現(xiàn)。
???? 所以,Pramatic精神不滅。這個系列就是探尋最適合自己的Spring+Hibernate模式。
????
????????????????????????????? I-配置文件簡化
?????我厭倦一切配置文件繁重的框架。
???? 最好的情況是,框架提供極端靈活復雜的配置方式,但只在你需要的時候。
?
???? Spring提供了三種可能來簡化XML。隨著國內(nèi)用戶水平的提高,這些基本的簡化技巧大家都已掌握。
?????大家可以直接看第3,第4點--Spring 1.2, Spring 2.0的后繼改進。
1.1.autowire="byName" /"byType"
???? 假設(shè)Controller有一個屬性名為customerDAO,Spring就會在配置文件里查找有沒有名字為CustomerDAO的bean, 自動為Controller注入。
?????如果bean有兩個屬性,一個想默認注入,一個想自定義,只要設(shè)定了autowire,然后顯式的聲明那個想自定義的,就可以達到要求。這就應了需求,在需要特別配置的時候就提供配置,否則給我一個默認注入。
???? 還有一個更懶的地方,在最最根部的<beans>節(jié)點寫一句default-autovwrie="byName",可以讓文件里的所有bean 都默認autowrie。
??? 不過Rod認為開發(fā)期可以這樣,但Production Server上不應該使用Autowire。而我覺得那些自定義一次的地方比如TranscationManager應該詳細定義,而Dao,Controller這種大量重復定義的bean就可以偷點懶了。
1.2.<bean>節(jié)點之間抽象公共定義和 Inner Bean
??? 這太方便懶人了,想不到兩個獨立的XML節(jié)點都可以玩繼承和派生,子節(jié)點擁有父節(jié)點的全部屬性。
??? 最好用的地方就是那個Transtion Proxy的定義。先定義一個又長又冗的父類,然后用子類去繼承它。
???
??? 另外,還有一個Inner Bean的機制,可以把DAO寫成Proxy的內(nèi)部類。為什么要寫成內(nèi)部類?為了讓Proxy冒名頂替它去讓Controller Autowire。(詳見后面的示例)
1.3. 寬松的配置, To XML or Not to XML?
??? 據(jù)說Spring比Struts的配置寬松了很多,這就給人把東西從配置文件中撤回原碼中的機會。
??? 不贊成什么都往配置文件里曬,造成了Rich Information的配置文件,修改或者查看的時候,要同時打開配置文件和原碼才能清楚一切。
??? 而我希望配置文件就集中做一些整體的配置,還有框架必須的、無需管理的冗余代碼。而一些細節(jié)的變化不大的配置和邏輯,就盡量別往里塞了。因此,Success/Fail View 的配置,不建議放在里面。
2.簡化后的配置文件
1.Controller只剩下一句
2.DAO也只剩一句
3.Service類只剩下5行
????????<property?name="target">
????????????<bean?class="org.springside.bookstore.service.CustomerManager"/>
????????</property>
????</bean>
3.Spring 1.2后xml語法簡化
?最主要的簡化是把屬性值和引用bean從子節(jié)點變回了屬性值,對不喜歡autowire的兄弟比較有用。
?當然,如果value要CDATA的時候還是要用子節(jié)點。另外,list的值可以用空格隔開也比較實用。

? </property>
? 簡化為
? <property?name="foo"?value="fooValue"/>

2.引用 bean





3. list可以簡化為空格分開的字符串



??????? <value>wuyu</value>





??
4.Spring 2.0來了
?? 如果沒什么外力刺激,spring xml 可能就這樣不會變了。但現(xiàn)在xml成了過街老鼠,被ror的默認配置和JDK5的annotation逼得不行,當然就要繼續(xù)求變。
?? 比如有好事者認為,節(jié)點名必須以bean打頭,附加一個屬性id來表示bean名;屬性值必須搞一個property子節(jié)點,子節(jié)點上有個屬性name來表示屬性名,是給機器看的很不直觀的東西。
?<property?name="maxCount"?value="10">
</bean>
給人看的東西應該就寫成
Spring 2.0正用schema實現(xiàn)類似的語法,具體請看它的JPetStore sample。
??? 如果沒有用Eclipse的Spring插件,那至少也要使用spring自帶的dtd使XML編輯器smart一些,能夠自動為你生成屬性,判斷節(jié)點/屬性名稱有沒有拼錯等。
6.還有更變態(tài)的簡化配置方法
?? ?比如autoproxy,不過我覺得更簡化就不可控了,所以沒有采用。
因為Spring自帶的sample離我們的實際項目很遠,所以官方一點的model層模式展現(xiàn)就靠Appfuse了。
????但Appfuse的model層總共有一個DAO接口、一個DAOImpl類、一個Service接口、一個ServiceImpl類、一個DataObject.....大概只有受慣了虐待的人才會欣然接受吧。
??? 另外,Domain-Driven逢初一、十五也會被拿出來討論一遍。
??? 其實無論什么模式,都不過是一種人為的劃分、抽象和封裝。只要在團隊里理解一致,自我感覺優(yōu)雅就行了。
???? 我的建議是,一開始DO和Manager一生一旦包演全場,DO作為純數(shù)據(jù)載體,而Manager類放置商業(yè)方法,用getHibernateTemplate()直接訪問數(shù)據(jù)庫,不強制基于接口編程。當某天系統(tǒng)復雜到你直覺上需要將DAO層和Service層分開時,再分開就好了。
??? 1.DataObject類
???? 好聽點也可以叫Domain Object。Domain Driven? Development雖然誘人,但因為Java下的ORM框架都是基于Data Mapper模式的,沒有Ruby On Rails中那種Active Recorder的模式。所以,還是壓下了這個欲望,Data Object純粹作一個數(shù)據(jù)載體,而把數(shù)據(jù)庫訪問與商業(yè)邏輯操作統(tǒng)一放到Manager類中。
??? 2.Manager類
????我的Manager類是Appfuse中DAO類與Service類的結(jié)合體,因為:
????2.1 不想使用純DAO
???? 以往的DAO是為了透明不同數(shù)據(jù)庫間的差異,而現(xiàn)在Hibernate已經(jīng)做的很好。所以目前純DAO的更大作用是為了將來可以切換到別的ORM方案比如iBatis,但一個Pragmaic的程序員顯然不會無聊到為了這個機會不大的理由,現(xiàn)在就去做一個純DAO層,項目又不是Appfuse那樣為了demo各種ORM方案而存在。
??? 2.2 也不使用純的薄Service層
??? 在JPetStore里有一個很薄的Service層,F(xiàn)ascade了一堆DAO類,把這些DAO類的所有方法都僵硬的重復了一遍。而我認為Fascade的意義在二:
????一是Controller調(diào)用Manager甲的時候,總會伴隨著調(diào)用Manager乙的某些方法。使用Fascade可以避免Controller零散的調(diào)用一堆Manager類。
????二是一個商業(yè)過程里可能需要同時調(diào)用DAO甲乙丙丁的方法。?
?????這些時候,F(xiàn)ascade都是合理的。但我討厭類膨脹,所以我寧愿在甲乙丙丁中挑一個來充當Fascade的角色。有耦合的問題嗎?對一個不是死搬書的Designer來說,組件邊界之內(nèi)的類之間的耦合并不是耦合。
??? 3.去除不必要的基于接口編程
??? 眾所周知,Spring是提倡基于接口編程的。
??? 但有些Manager類,比如SaleOrderManager ,只有5%的機會再有另一個Impl實現(xiàn)。95%時間里這兩兄弟站一起,就像C++里的.h和.cpp,徒增維護的繁瑣(經(jīng)常要同步兩個文件的函數(shù)聲明),和代碼瀏覽跳轉(zhuǎn)時的不便(比如從Controler類跟蹤到Service類時,只能跳轉(zhuǎn)到接口類的相應函數(shù),還要再按一次復雜的熱鍵才跳轉(zhuǎn)到實現(xiàn)類)
??? 連Martin Flower都說,強制每個類都分離接口和實現(xiàn)是過猶不及。只在有多個獨立實現(xiàn),或者需要消除對實現(xiàn)類的依賴時,才需要分離接口。
????3.1 DAO被強制用接口的原因
??? Spring IOC本身是不會強制基于接口的,但DAO類一般要使用Spring的聲明式事務機制,而聲明式的事務機制是使用Spring AOP來實現(xiàn)的。Spring AOP的實現(xiàn)機制包括動態(tài)代理和Cgilib2,其中Spring AOP默認使用的Java動態(tài)代理是必須基于接口,所以就要求基于接口了。
????
??? 3.2 解決方法
??? 那就讓Spring AOP改用CGLib2,生成目標類的子類吧,我們只要指定使用聲明式事務的FactoryBean使用CGLib的方式來實現(xiàn)AOP,就可以不基于接口編程了。
??? 指定的方式為設(shè)置proxyTargetClass為true。如下:







???? 又因為這些Service Bean都是單例,效率應該不受影響。
??? 4.總結(jié)
??? 對比Appfuse里面的5個類,我的Model層里只有VO作為純數(shù)據(jù)載體,Manager類放商業(yè)方法。有人說這樣太簡單了,但一個應用,要劃成幾個JSP,一個Controller,一個Manager,一個VO,對我來說已經(jīng)足夠復雜,再要往上架墻疊屋,恕不奉陪,起碼在我的項目范圍里不需要。(但有很多項目是需要的,神佑世人)
??? 后記:迫于世人的壓力,SpringSide還是把DAO和Service層分開了,但依然堅持不搞那么多接口。
Struts與Webwork的扇子請?zhí)^本篇。
??? MVC不就是把M、V、C分開么?至唯物樸素的做法是兩個JSP一個負責View,一個負責Controller,再加一個負責Model的Java Bean,已經(jīng)可以工作得很好,那時候一切都很簡單。
??? 而現(xiàn)在為了一些不是本質(zhì)的功能,冒出這么多非標準的Web框架,實在讓人一陣郁悶。像Ruby On Rails那樣簡捷開發(fā),可用可不用,而且沒有太多的限制需要學習的,比如Webwork這型還可以考慮。但像Struts那樣越用框架越麻煩,或者像Tapestry那樣有嚴重自閉傾向,額上鑿著"高手專用玩具"的,用在團隊里就是不負責任的行為了。
1. 原理
???? 我們的Controller層,就是實現(xiàn)handleRequest(request,response)函數(shù)的普通JavaBean。
2. 優(yōu)勢
???? Spring MVC與struts相比的優(yōu)勢:
?
????? 如果需要application對象,比如想用application.getRealPath()時,就要extends webApplicationObjectSupport。
3.2.每個Controler負責一組相關(guān)的action
?????? 以上三者都是把URL參數(shù)直接反射為Controller的函數(shù),而Stripes的設(shè)計可用annotation標注url action到響應函數(shù)的映射。
3.5.提取基類
??????
???? ?經(jīng)過化簡再化簡,已經(jīng)是很簡單一個Java Bean ,任誰都可以輕松上手,即使某年某月技術(shù)的大潮把現(xiàn)在所有MVC框架都淹沒了,也不至于沒人識得維護。
人生像個舞臺,請良家少女離開。
????同樣的,F(xiàn)reemarker和Velocity愛好者請?zhí)^本篇。與棄用webwork而單用Spring MVC Controller接口的理由一樣,Freemarker本來是一樣好東西,還跨界支持jsp?的taglib,而且得到了WebWork的全力支持,但為了它的非標準化,用戶數(shù)量與IDE的缺乏,在View層我們還是使用了保守但人人會用,IDE友好的JSP2.0 配合JSTL。
??? 對于B/S結(jié)構(gòu)的企業(yè)應用軟件來說,基本的頁面不外兩種,一種是填Form的,一種是DataGrid 數(shù)據(jù)列表管理的,再配合一些css, js, ajax的效果,就是View層要關(guān)注的東西了。
1. JSP 2.0的EL代替<c:out>
JSP2.0可以直接把EL寫在html部分,而不必動用<c:out>節(jié)點后,老實說,JSP2.0+JSTL達到的頁面效果,已不比Velocity相差多少了。
代替
<p><c:out?value="{goods.name}"/></p>
(除了EL里面不能調(diào)用goods的函數(shù),sun那幫老頑固始終堅持JSTL只能用于數(shù)據(jù)顯示,不能進行數(shù)據(jù)操作,所以不能調(diào)用bean的get/set外的方法)
?2. 最懶的form 數(shù)據(jù)綁定
??? Spring少得可憐的幾個tag基本上是雞肋,完全可以不要。 而Spring開發(fā)中的那些Simple Form tag又還沒有發(fā)布。Spring的Tag主要用來把VO的值綁到input框上。但是,和Struts一樣,需要逐個Input框綁定,而且語法極度冗長,遇到select框還要自己進行處理.....典型的Spring Sample頁面讓人一陣頭暈.
??? 而jodd的form tag給了我們懶人一個懶得多的方法,只要在<form>兩頭用<jodd:form bean="myVO"></jodd:form>包住,里面的所有input框,select框,checkBox...統(tǒng)統(tǒng)自動被綁定了,這么簡單的事情,真不明白struts,spring為什么不用,為了不必要的靈活性么?
<jodd:form?bean="human">
<input?type="text"?name="name">
<input?type="radiobox"?name="sex"?value="man">
<select?name="age">
??<option?value="20">20</option>
??<option?value="30">30</option>
</select>
</jodd:form>
</form>?

這是因為它的beanUtils比Jakata Common弱,用了一個錯誤的思路的緣故。 動用beanUtils修改一下就可以了,修改后的源碼可以在這里下載。
3. DataGrid數(shù)據(jù)列表
DisplayTag和ValueList都屬于這種形式的Tag Library。但最近出現(xiàn)的Extreme Table是真正的killer,他本身功能強大不說,而且從一開始就想著如何讓別人進行擴展重載,比如Extend Attributes機制就是DisplayTag這樣的讓千人一面者不會預留。
4.css, java script, ajax
天下紛擾,沒有什么特別想講想推薦的,愛誰誰吧。Buffalo, DWR, Scriptaculous, Prototype, AjaxTags, AjaxAnywhere, Rico, Dojo, JSON-RPC,看著名字就頭痛。