如何編寫一份優雅的Spring配置檔案
前言
眾所周知,Spring最大的特點就是控制反轉,而實現控制反轉就是通過那一系列的配置檔案。平時筆者在開發過程中也寫過不少XML配置檔案,但大部分都是基於現有的配置檔案稍作修改,很多標籤內容只能做到“知其然卻不知其所以然”,而有很多標籤根本不知其然,所以便抽時間認真學習一下相關內容,希望能夠編寫一份優雅的Spring配置檔案。
宣告
隨便開啟一份Spring工程的配置檔案,第一行基本上都如下所示:
<?xml version="1.0" encoding="UTF-8"?>
從字面意義基本就能知道大概是關於版本和編碼資訊的,而事實也的確如此。1998年,W3C就釋出了XML1.0規範,也許將來會發布新版本,但是目前仍然是1.0版本。encoding是編碼宣告,代表xml檔案採用utf-8的編碼格式。
需要注意的是,XML 宣告通常在 XML 文件的第一行出現。 XML 宣告不是必選項,但是如果使用 XML 宣告,必須在文件的第一行,前面不得包含任何其他內容或空白。
正文
宣告資訊之後,就是配置檔案的正文了,內容基本上如下所示:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
//具體配置資訊
</beans>
beans標籤是整個配置檔案的根節點,包含一個或者多個bean元素
,而我們的學習也從這裡展開。
名稱空間
xmlns
XML NameSpace的縮寫,因為XML檔案的標籤名稱都是自定義的,自己寫的和其他人定義的標籤很有可能會重複命名,而功能卻不一樣,Spring預設的名稱空間就是http://www.springframework.org/schema/beans
。Spring容器在解析xml檔案時,會獲取標籤的名稱空間來跟上述url比較,判斷是否為預設名稱空間。
xmlns:xsi
全名xml schema instance,是指具體用到的schema資原始檔裡定義的元素所準守的規範。即http://www.w3.org/2001/XMLSchema-instance
這個檔案裡定義的元素遵守什麼標準 。
xsi:schemaLocation
本文件裡的xml元素所遵守的規範,這些規範都是由官方制定的,可以進你寫的網址裡面看版本的變動。xsd的網址還可以幫助你判斷使用的程式碼是否合法。
那麼問題來了,感覺上述資訊都要線上驗證,如果我的應用離線執行,那怎麼辦呢?Spring也考慮到了這個問題,所以都會在jar包中附帶上相應的的xsd檔案。通常,META-INF目錄下有如下spring.handlers和spring.schemas兩個檔案,我們以spring 2.5.6為例,進入相應檔案:
spring.handlers檔案內容:
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/jms=org.springframework.jms.config.JmsNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
spring.schemas檔案內容:
http\://www.springframework.org/schema/aop/spring-aop-2.0.xsd=org/springframework/aop/config/spring-aop-2.0.xsd
http\://www.springframework.org/schema/aop/spring-aop-2.5.xsd=org/springframework/aop/config/spring-aop-2.5.xsd
http\://www.springframework.org/schema/aop/spring-aop.xsd=org/springframework/aop/config/spring-aop-2.5.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans-2.0.xsd
http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
http\://www.springframework.org/schema/beans/spring-beans.xsd=org/springframework/beans/factory/xml/spring-beans-2.5.xsd
http\://www.springframework.org/schema/context/spring-context-2.5.xsd=org/springframework/context/config/spring-context-2.5.xsd
http\://www.springframework.org/schema/context/spring-context.xsd=org/springframework/context/config/spring-context-2.5.xsd
http\://www.springframework.org/schema/jee/spring-jee-2.0.xsd=org/springframework/ejb/config/spring-jee-2.0.xsd
http\://www.springframework.org/schema/jee/spring-jee-2.5.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd
http\://www.springframework.org/schema/jee/spring-jee.xsd=org/springframework/ejb/config/spring-jee-2.5.xsd
http\://www.springframework.org/schema/jms/spring-jms-2.5.xsd=org/springframework/jms/config/spring-jms-2.5.xsd
http\://www.springframework.org/schema/jms/spring-jms.xsd=org/springframework/jms/config/spring-jms-2.5.xsd
http\://www.springframework.org/schema/lang/spring-lang-2.0.xsd=org/springframework/scripting/config/spring-lang-2.0.xsd
http\://www.springframework.org/schema/lang/spring-lang-2.5.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd
http\://www.springframework.org/schema/lang/spring-lang.xsd=org/springframework/scripting/config/spring-lang-2.5.xsd
http\://www.springframework.org/schema/tx/spring-tx-2.0.xsd=org/springframework/transaction/config/spring-tx-2.0.xsd
http\://www.springframework.org/schema/tx/spring-tx-2.5.xsd=org/springframework/transaction/config/spring-tx-2.5.xsd
http\://www.springframework.org/schema/tx/spring-tx.xsd=org/springframework/transaction/config/spring-tx-2.5.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.0.xsd=org/springframework/beans/factory/xml/spring-tool-2.0.xsd
http\://www.springframework.org/schema/tool/spring-tool-2.5.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
http\://www.springframework.org/schema/tool/spring-tool.xsd=org/springframework/beans/factory/xml/spring-tool-2.5.xsd
http\://www.springframework.org/schema/util/spring-util-2.0.xsd=org/springframework/beans/factory/xml/spring-util-2.0.xsd
http\://www.springframework.org/schema/util/spring-util-2.5.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
http\://www.springframework.org/schema/util/spring-util.xsd=org/springframework/beans/factory/xml/spring-util-2.5.xsd
兩個檔案的內容都是常量的定義,值都是jar包的路徑,開啟對應的檔案可以知道,xsd檔案是名稱空間schema的定義檔案,而*Namespacehandler檔案則負責將定義的xml檔案資訊註冊Spring容器中,具體的邏輯其實可以參考spring容器的啟動過程,此處不再贅述。
import標籤
在實際開發過程中,一些大型專案會將配置資訊按照不同的模組劃分成多個配置檔案,spring import標籤就可以達到此目的,我們會經常看到如下的配置資訊:
<import resource="file:..."/>
<import resource="classpath:..."/>
- file:表示使用檔案系統的方式尋找後面的檔案(檔案的完整路徑)
- classpath:相當於/WIN-INF/classes/,如果使用了classpath,那就表示只會到你的class路徑中去查詢檔案
- classpath*:表示不僅會在class路徑中去查詢檔案,還會在jar中去查詢檔案
需要注意的是,Spring採取遞迴的方式解析import標籤,很可能會出現變數無法解析的情況,如果存在變數引用的情況,需要注意。
context標籤
spring從2.5版本開始支援註解注入,註解注入可以省去很多的xml配置工作。由於註解是寫入java程式碼中的,所以註解注入會失去一定的靈活性,我們要根據需要來選擇是否啟用註解注入。
<context:annotation-config />
<context:component-scan base-package="xxxxxxxxx"/>
前者的作用是隱式地向Spring容器註冊AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、PersistenceAnnotationBeanPostProcessor、RequiredAnnotationBeanPostProcessor 這 4 個BeanPostProcessor。
後者啟用了對類包進行掃描以實施註釋驅動 Bean 定義的功能,同時還啟用了註釋驅動自動注入的功能。當使用 < context:component-scan/ > 後,就可以將 < context:annotation-config/ > 移除了。base-package 屬性指定了需要掃描的類包,類包及其遞迴子包中所有的類都會被處理。
aop標籤
<aop:aspectj-autoproxy/>
<aop:config>
<aop:aspect id = "aspectXML" ref="actionAspectXML">
<aop:pointcut id="anyMethod" expression="execution(* com.maowei.learning.aop.ActionImpl.*(..))"/>
<aop:before method="beforeMethod" pointcut-ref="anyMethod"/>
<aop:after method="afterMethod" pointcut-ref="anyMethod"/>
<aop:after-returning method="afterReturningMethod" pointcut-ref="anyMethod"/>
<aop:after-throwing method="afterThrowMethod" pointcut-ref="anyMethod"/>
<aop:around method="aroundMethod" pointcut-ref="anyMethod"/>
</aop:aspect>
</aop:config>
aop:aspectj-autoproxy
宣告自動為spring容器中那些配置@aspectJ切面的bean建立代理,織入切面。它有一個proxy-target-class屬性,預設為false,表示使用jdk動態代理織入增強,當配為true時,表示使用CGLib動態代理技術織入增強。不過即使proxy-target-class設定為false,如果目標類沒有宣告介面,則spring將自動使用CGLib動態代理。
aop:aconfig
便是具體的AOP資訊了,具體內容可以檢視相關內容,不再贅述。
bean標籤
bean標籤
在配置檔案中最常見,具體的格式有如下幾種:
<bean id = "bean例項名" class="bean類全名" />
<bean id = "bean例項名" class="bean類全名" scope="prototype" />
<bean id = "bean例項名" class="bean類全名" init-method="初始化時呼叫的方法" destory-method="物件銷燬時呼叫方法"/>
<bean id = "bean例項名" class="bean類全名" >
<property name="bean類的屬性名稱" ref="要引用的bean名稱"/>
<property name="bean類的屬性名稱" value="直接指定屬性值"/>
……
</bean>
<bean id = "bean例項名" class="bean類全名" >
<constructor-arg index="構造方法中引數的序號,從0開始計算" type="構造方法引數型別" value="引數值" />
<constructor-arg index="構造方法中引數的序號,從0開始計算" type="構造方法引數型別" ref="引用的bean名稱" />
</bean>
tx標籤
tx標籤
一般用於事務管理,常見的用法如下:
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*"
isolation="READ_COMMITTED"
propagation="REQUIRED"
timeout="100"/>
<tx:method name="get*"
read-only="100"/>
</tx:attributes>
</tx:advice>
上述配置檔案內容涵蓋了TransactionDefinition 事務定義資訊,具體解釋詳見《Spring 事務管理》。
總結
本文列出了spring配置檔案中常見的標籤,闡述了相關標籤的含義及使用注意點。紙上得來終覺淺,絕知此事要躬行,只有多多練習,才能寫出一份優雅的spring配置檔案。