Reduce Spring Xml Configuration
上一次 的 aop 移植裡,我提到想要將 spring xml 減化的構想,像下面的設定檔:
這樣 千篇一律的 DAO/ServiceImpl 的設定檔大家應該不漠生吧?現在我們來完全移除它,改以 annotation 的方式取代。 在進行之前,先聲明這樣的做法是 邪惡的。因為它違反了 Spring 的基本理念 -- 將 configuration 完全抽離 POJO。未來 Spring 可能也不會提類似的 solution,所以這些自創的 code 可能會增加維護上的負擔。
廢話講完了,開始吧。我們得想個法子能夠以程式的方式註冊 (register) 自己的 bean,subclass XmlApplicationContext 可能是其中之一的做法。不過我選擇比較簡單的 BeanFactoryPostProcessor。implement 這個 interface 的 bean, Spring 會在 建立好 BeanDefinition 和 instantiate bean 之間時呼叫 postProcessBeanFactory() 。換句話說時間點在讀完設定檔後,實際 new bean 之前。
AnnotatedBeanRegister 除了 implements BeanFactoryPostProcessor 之外,還多加 Ordered,有了這個就 能指定 Processor 執行優先順序。手動註冊 Bean 是讀完 xml 後馬上要做的第一件事,所以我設 HIGHEST_PRECEDENCE。
至於 postProcessBeanFactory() 裡,我們做三件事:
- findAnnotatedClassNames() 查出所有在 classpath 底下的 class 名稱
- 如果 class 具備 @TxService 這個 annotation,便利用 BeanDefinitionRegistry 註冊一個 bean 進去
- 如果 class 具備 @DAO 這個 annotation,也註冊一個 bean
findAnnotatedClassNames() 我用的是笨方法... 等一下在說。先看看 registerDAO():
ok,上面的 step by step 的說明應該很清楚了。凡是 class 上有註記 @DAO 者,預設以 class 的名稱為 bean name 、並依據名稱來做 Autowire,然後註冊該 class 到 BeanFactory 裡。同樣的做法可以套用在 @TxService,唯一 的差別是預設的 id 是用 class 的 interface 名稱來轉,這裡就不再贅述。
接下來是討厭的 findAnnotatedClassNames(),它要找出在 class path 裡的所有 class 名稱,這可難倒我了... 目前我找到的方法是利用掃出實際的 .class 檔案來反推 class 名稱:
我們利用了 spring 內建的 Resource 來取得 class file,所以享有 wildcard 的好處:
按上面的設定,可以找到所有 package 為 foo 的 .class 檔,findAnnotatedClassNames() 再依據這些檔案路徑 轉換為 class name。這個實做我只在 tomcat 上試過而已,如果在比較複雜的 class loader 環境,或是想找 jar file 裡的 class 可能就比較難了... 若有人知道更好的做法,請救救我吧~~
最後,替我們的 DAO 和 ServiceFacade 加上 annotation
搞定!短短幾個字就 ok 啦!不需要再替這些 bean 做繁鎖的 xml 定義了。而我們的 poincut 也可進化成:
除了原本的 exeuction(ServiceImpl) 之外,還可以加上所有具備 @TxService 的 class。這樣就不用限定 package 或是 class 名稱的命名了。
總結:
- 優: 不需要寫額外重覆的 xml,符合 DRY 原理
- 優: 沒有 xml 等於可以任意的 refactoring class/package,改完不用再心裡發毛啦
- 優: 預設使用 AutoWire.BY_NAME,by name 較 by type 來有的彈性多,而且不易錯。
- 優: 可以寫出更穩當的 pointcut
- 優: xml 設定檔大幅減少,加快啟動速度。
- 優: 設定很固定,簡單易懂。
- 劣: 太自動化了,很難搞懂來龍去脈
- 劣: 客製 annontation 做法非 Spring 標準,長期維護吃力
- 劣: 設定上缺乏變化,沒彈性。
顯然優點多於缺點 :-) 那我們可不可以繼續強化 AnnotatedBeanRegister ,增加更多的設定可能性:
我個人想法是 No! 如果需要特別的設定,Spring xml 仍是最好的地方,不該在 class 上註記一大堆的有的沒的 ,看的人真的會眼花。這就像是你在營幕旁貼了滿滿的小黃標,即混亂又礙眼,也沒有頭緒可言,它們真的有用嗎? 遇到這種情況,你需要的是一本萬用記事本 (即 xml 檔) 好好整理,而不是 Post It。上面我們實做的 @TxService 和 @DAO 則都完全沒額外的設定,盡量簡化。這份簡化是來自於長期的經驗,就好比你常常在白板上寫一些公事 ,寫久了自然就會有一些雷同的例行公事反覆不斷出現,你可以買個黃、綠、紅的小磁鐵,每個顏色各自代表那 些常做的事,這樣既簡明又快速。個人認為客製的 annotation 也該以這樣方向來設計,@TxService 和 @DAO 就是 我們專案裡粹練出來,用來簡化的小磁鐵。
致命的缺點一個就夠了
某種程度的落入了自圓其說的狀況
不過 還好這是技術文
由...發表 219.87.10.226 on 十月 18, 2006 at 01:56 下午 CST #
well, Blog 本來就是個自圓其說的地方... 就不要挑啦
如果內容經得起考驗的話,早就貼到 forum 裡去囉
anyway, 內文提到的技術討論只能說提供一個可能性,而該不該用、怎麼用又是另一回事了
我自個是用的蠻爽的,哈
由...發表 ingramchen on 十月 18, 2006 at 02:12 下午 CST #