1. 程式人生 > >如何編寫一份優雅的Spring配置檔案

如何編寫一份優雅的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配置檔案。