隨筆-295  評論-26  文章-1  trackbacks-0
          2007-07-18 Spring的事務通知???

          Spring2.0 可擴展XML配置初探

          關鍵字: Spring ? ????

          Spring 2.0版本支持擴展XML配置,著實興奮了一下,在我看來,Spring作為目前最流行的框架,不能擴展用戶自定義的配置,實在是Spring的一個很不爽的地方,<bean />的方式用起來比較通用,起碼到目前為止符合大部分人的使用習慣,并且能完成Spring所有的配置操作,但是對于第三方的提供商或則會經常擴展Spring功能的開發者來說,使用<bean />這樣的配置方式或許不是他們最想要的,他們需要使組件的配置更加直觀、易閱讀、易擴展……試想使用下面的配置方式

          代碼
          1. <mytag:datasource?id= "datasource" ? ??
          2. ???????databaseType= "oracle" ? ??
          3. ???????ip= "192.168.1.110" ? ??
          4. ???????port= "1521" ? ??
          5. ???????databaseName= "myDB" ??
          6. ???????userName= "admin" ??
          7. ???????password= "password" ??
          8. ???????/> ??
          9. ??
          10. <mytag:ehCache?id= "ehcache" ? ??
          11. ???????cache= "true" ? ??
          12. ???????maxElements= "100000" ? ??
          13. ???????timeToIdleSeconds= "120" ? ??
          14. ???????timeToLiveSeconds= "120" ??
          15. ???????overflowToDisk= "true" ??
          16. ???????/> ??

          上面的代碼中配置了兩個組件,datasource和cache組件,相比普通的bean&propertiy方式,很顯然,這種配置方式更直觀,更易讀,更重要的是,如果作為組件發布,使用者也可以很方便快捷的開始使用,而不需要關心組件的任何實現細節。

          擴展XML配置大致需要一下幾個步驟
          1、創建一個需要擴展的組件
          2、定義一個xsd文件描述組件內容
          3、創建一個文件,實現BeanDefinitionParser接口,用來解析xsd文件中的定義和組件定義
          4、創建一個Handler文件,擴展自NamespaceHandlerSupport,目的是將組件注冊到Spring容器
          5、編寫spring.handlers和spring.schemas文件

          提供一個簡單的例子,來說明如何去擴展一個Spring配置,需求如下:使用自定義標簽定義一個簡單的bean,這個bean有一個或多個屬性,標簽定義完成后,可以在其他項目中用自定義標簽來定義該bean。

          首先,創建一個需要擴展的組件,在這里只是一個簡單的bean,而且這個bean只有一個屬性age.
          One.java

          代碼
          1. package?com.mysite.tag; ??
          2. ??
          3. public?class?One?{ ??
          4. ????private?String?age; ??
          5. ???? ??
          6. ????public?One(){ ??
          7. ???????? ??
          8. ????} ??
          9. ??
          10. ????public?String?getAge()?{ ??
          11. ????????return?age; ??
          12. ????} ??
          13. ??
          14. ????public?void?setAge(String?age)?{ ??
          15. ????????this.age?=?age; ??
          16. ????} ??
          17. } ??

          然后,建立一個xsd文件,來描述這個bean
          mytag.xsd

          代碼
          1. <?xml?version="1.0"?encoding="UTF-8"?>??
          2. <xsd:schema?xmlns="http://www.mysite.org/schema/mytag"??
          3. ????????xmlns:xsd="http://www.w3.org/2001/XMLSchema"??
          4. ????????xmlns:beans="http://www.springframework.org/schema/beans"??
          5. ????????targetNamespace="http://www.mysite.org/schema/mytag"??
          6. ????????elementFormDefault="qualified"??
          7. ????????attributeFormDefault="unqualified">??
          8. ???? ??
          9. ????<xsd:import?namespace="http://www.springframework.org/schema/beans"/>??
          10. ???? ??
          11. ????<xsd:element?name="one">??
          12. ????????<xsd:complexType>??
          13. ????????????<xsd:complexContent>??
          14. ????????????????<xsd:extension?base="beans:identifiedType">??
          15. ????????????????????<xsd:attribute?name="age"?type="xsd:string"?default="99999"/>??
          16. ????????????????</xsd:extension>??
          17. ????????????</xsd:complexContent>??
          18. ????????</xsd:complexType>??
          19. ????</xsd:element>??
          20. </xsd:schema>??

          在上面的xsd文件描述了一個新的targetNamespace,并在這個空間中定義了一個name為one的element,one有一個age屬性,類型為string,默認值為99999.xsd文件是xml DTD的替代者,使用XML Schema語言進行編寫,這里對xsd schema不做太多解釋,有興趣可以參考相關的資料。

          創建一個Java文件,該文件實現了BeanDefinitionParser接口,用來解析xsd文件中的定義并注冊到組件中。
          MyBeanDefinitionParser.java

          代碼
          1. package?com.mysite.tag; ??
          2. ??
          3. import?org.springframework.beans.factory.config.BeanDefinition; ??
          4. import?org.springframework.beans.factory.config.BeanDefinitionHolder; ??
          5. import?org.springframework.beans.factory.support.BeanDefinitionReaderUtils; ??
          6. import?org.springframework.beans.factory.support.RootBeanDefinition; ??
          7. import?org.springframework.beans.factory.xml.BeanDefinitionParser; ??
          8. import?org.springframework.beans.factory.xml.ParserContext; ??
          9. import?org.w3c.dom.Element; ??
          10. ??
          11. public?class?MyBeanDefinitionParser?implements?BeanDefinitionParser{ ??
          12. ????public?BeanDefinition?parse(Element?arg0,?ParserContext?arg1)?{ ??
          13. ????????RootBeanDefinition?def?=?new?RootBeanDefinition(); ??
          14. ????????????????//設置Bean?Class ??
          15. ????????def.setBeanClass(One.class); ??
          16. ???????? ??
          17. ????????????????//注冊ID屬性 ??
          18. ????????String?id?=?arg0.getAttribute("id"); ??
          19. ????????BeanDefinitionHolder?idHolder=?new?BeanDefinitionHolder(def,id); ??
          20. ????????BeanDefinitionReaderUtils.registerBeanDefinition(idHolder,?arg1.getRegistry()); ??
          21. ???????? ??
          22. ????????????????//注冊age屬性 ??
          23. ????????String?age?=?arg0.getAttribute("age"); ??
          24. ????????BeanDefinitionHolder?ageHolder=?new?BeanDefinitionHolder(def,age); ??
          25. ????????BeanDefinitionReaderUtils.registerBeanDefinition(ageHolder,?arg1.getRegistry()); ??
          26. ????????def.getPropertyValues().addPropertyValue("age",?age); ??
          27. ???????? ??
          28. ????????return?def; ??
          29. ????} ??
          30. } ??
          31. ??

          上面的代碼僅僅實現了一個方法public BeanDefinition parse(Element arg0, ParserContext arg1),設置相關的Bean Class,解析了對應的xsd文件,并將解析的內容注冊到上下文中,同時返回一個BeanDefinition對象(BeanDefinition是Spring的bean定義,提供了bean部分的操作方法,如isSingleton()、isLazyInit()等)。

          注意,id屬性是一個默認的屬性,可以不在xsd文件中描述,但是需要注冊它,否則將無法通過getBean方法獲取標簽定義的bean,也無法被其他bean引用。
          另外,下面代碼是給bean的屬性賦值,這個是不可缺少的,否則在使用標簽定義時將無法獲取bean屬性的值。

          代碼
          1. def.getPropertyValues().addPropertyValue("age",?age); ??

          然后為組件編寫一個Handler文件,擴展自NamespaceHandlerSupport,它的作用是將組件注冊到Spring容器
          MyNameSpaceHandler.java

          代碼
          1. package?com.mysite.tag; ??
          2. ??
          3. import?org.springframework.beans.factory.xml.NamespaceHandlerSupport; ??
          4. ??
          5. public?class?MyNameSpaceHandler?extends?NamespaceHandlerSupport?{ ??
          6. ??
          7. ????public?void?init()?{ ??
          8. ?????????registerBeanDefinitionParser("one",new?MyBeanDefinitionParser()); ??
          9. ????} ??
          10. } ??

          實際執行的過程只有一句代碼,注冊了一個名字為one的擴展配置,包含了MyBeanDefinitionParser所parser相關xsd的內容。

          到了這里,一個Spring擴展標簽已經完成,但是我們目前還沒辦法使用它,Spring沒那么聰明,它無法知道我們在什么地方定義了哪些擴展標簽,這些標簽將被誰解析,這個過程要我們通過一些文件來告知Spring知道,它們就是spring.handlers和spring.schemas,它們放在META-INF目錄中,Spring.jar的META-INF目錄中也有同名的文件,它們的文件內容基本上是相似的,而Spring在執行過程中,如果發現其他jar文件的META-INF文件夾中包含有這兩個文件,Spring將會合并它們。
          spring.schemas

          代碼
          1. http\://www.mysite.org/schema/mytag.xsd=com/mysite/tag/mytag.xsd ??

          spring.handlers

          代碼
          1. http\://www.mysite.org/schema/mytag=com.mysite.tag.MyNameSpaceHandler ??

          spring.schemas將告訴Spring配置文件知道,如果在配置中引用http://www.mysite.org/schema/mytag.xsd,它應該去什么地方找相應的xsd文件。
          而spring.handlers文件將告訴Spring,應該使用哪個Handler注冊擴展標簽。

          現在為止,一個完整的xml擴展標簽全部完成,做一個小應用測試一下。
          將整個項目打包成jar文件(別忘記META-INF內的兩個文件),然后新建一個項目,引用剛才打包的jar文件,并引用Spring相關文件。
          需要注意,自定義xml擴展配置只有xsd方式的引用才可以使用.
          application.xml

          代碼
          1. <?xml?version="1.0"?encoding="UTF-8"?>??
          2. <beans?xmlns="http://www.springframework.org/schema/beans"??
          3. ????xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"??
          4. ????xmlns:tag="http://www.mysite.org/schema/mytag"??
          5. ????xsi:schemaLocation="http://www.springframework.org/schema/beans ??
          6. ????http://www.springframework.org/schema/beans/spring-beans-2.0.xsd ??
          7. ????http://www.mysite.org/schema/mytag ??
          8. ????http://www.mysite.org/schema/mytag.xsd">??
          9. ??
          10. ????<tag:one?id="oneBean"?age="99"/>??
          11. </beans>??

          在xml文件引用上可以看到,配置了一個名字為tag的名稱空間,目標為http://www.mysite.org/schema/mytag命名空間,這個目標名稱空間必須是存在于項目的引用中的(mytag.xsd中所定義的).
          代碼
          1. <tag:one?id="oneBean"?age="99"/> ??

          上面定義了一個id為oneBean的組件,使用了“one”擴展標簽,也就是我們在handler中所注冊的,組件age屬性的值為99。

          Main.java

          代碼
          1. package?com.test; ??
          2. ??
          3. import?org.springframework.context.ApplicationContext; ??
          4. import?org.springframework.context.support.ClassPathXmlApplicationContext; ??
          5. ??
          6. import?com.mysite.tag.One; ??
          7. ??
          8. public?class?Main?{ ??
          9. ??
          10. ????public?static?void?main(String[]?args)?{ ??
          11. ????????ApplicationContext?ctx?=?new?ClassPathXmlApplicationContext("application.xml"); ??
          12. ????????One?tag?=?(One)?ctx.getBean("oneBean"); ??
          13. ????????System.out.println("oneBean?age?is?"+tag.getAge()); ??
          14. ????} ??
          15. } ??

          運行測試程序,結果如下
          代碼
          1. oneBean?age?is?99??

          Spring的xml擴展是一個非常有用的特性,在Spring2.0的版本中也提供了一些新的標簽使用,如<aop>,<tx>等,但就目前來講受大家關注程度并不高,我想大部分使用Spring的開發人員都在使用Spring開發企業應用,而Spring所提供的<bean />定義的方式對于開發人員來說已經能夠滿足需要,但是如果看的更遠一些,在Spring以后的發展過程中,xml擴展應該會成為spring的核心特性之一,或許到時大家會習慣這樣的方式來編寫Spring配置文件吧

          代碼
          1. <XXCompany:XXXModule?id=""> ??
          2. ... ??
          3. ... ??

          最后更新:2007-07-18 16:03
          15:42??|?? 永久鏈接??|?? 瀏覽?(481)??|?? 評論?(2)??| ?? 收藏??|?? 進入論壇??|??
          評論 ???共 2 條 發表評論
          baallee ??? 2007-07-18 15:53

          代碼
          1. <? xml ? version = "1.0" ? encoding = "UTF-8" ?> ? ??
          2. < beans ? xmlns = "http://www.springframework.org/schema/beans" ???? ??
          3. xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" ???? ??
          4. xmlns:p = "http://www.springframework.org/schema/p" ???? ??
          5. xsi:schemaLocation ="http://www.springframework.org/schema/beans???????? ??
          6. http://www.springframework.org/schema/beans/spring-beans.xsd" > ?? ??
          7. < bean ? class = "com.interface21.spring2.ioc.Person" ????? ??
          8. p:name = "Tony" ???? ??
          9. p:age = "53" ????? ??
          10. p:house-ref = "number10" ? /> ??? ??
          11. < bean ? class = "com.interface21.spring2.ioc.House" ????? ??
          12. id = "number10" ???? ??
          13. p:name = "10?Downing?Street" /> ?? ??
          14. </ beans > ??

          對于簡單的應用可以用p標簽就好了。
          自定意擴展應該用在更多的高級應用上



          大盤預測 國富論
          posted on 2007-08-29 15:08 華夢行 閱讀(269) 評論(0)  編輯  收藏 所屬分類: Spring
          主站蜘蛛池模板: 襄垣县| 罗山县| 侯马市| 高要市| 沁源县| 沁水县| 潍坊市| 博野县| 双牌县| 云梦县| 会泽县| 栾城县| 栾川县| 麻城市| 蓬莱市| 理塘县| 宜章县| 海丰县| 远安县| 武宁县| 临朐县| 隆尧县| 嘉黎县| 台江县| 江门市| 平江县| 正蓝旗| 砚山县| 宁海县| 兴和县| 乳源| 大渡口区| 依兰县| 迭部县| 佛学| 莒南县| 台山市| 景洪市| 察雅县| 龙里县| 清水县|