如果bean本身将通過某種動态過程來确定和提供資源路徑,那麼bean可以使用resourceloader接口來加載資源。 j假設以某種方式加載一個模闆,其中需要的特定資源取決于使用者的角色。 如果資源是靜态的,那麼完全消除resourceloader接口的使用是有意義的,隻需讓bean公開它需要的resource屬性,那麼它們就會以你所期望的方式被注入。
什麼使得它們輕松注入這些屬性,是所有應用程式上下文注冊和使用一個特殊的javabeans propertyeditor,它可以将string路徑轉換為resource對象。 是以,如果mybean具有“資源”類型的模闆屬性,則可以使用該資源的簡單字元串進行配置,如下所示:
請注意,資源路徑沒有字首,因為應用程式上下文本身将用作resourceloader,資源本身将通過classpathresource,filesystemresource或servletcontextresource(根據需要)加載,具體取決于上下文的确切類型。
如果需要強制使用特定的資源類型,則可以使用字首。 以下兩個示例顯示如何強制使用classpathresource和urlresource(後者用于通路檔案系統檔案)。
(某一特定)應用上下文的構造器通常可以使用字元串或字元串數組所指代的(多個)資源(如 xml 檔案)來構造目前上下文。
當指定的位置路徑沒有帶字首時,那從指定位置路徑建立的 resource 類型(用于後續加載 bean 定義),取決于所使用應用上下文。舉個列子,如下所建立的 classpathxmlapplicationcontext :
會從類路徑加載 bean 的定義,因為所建立的 resource 執行個體是 classpathresource.但所建立的是 filesystemxmlapplicationcontext 時,
則會從檔案系統加載 bean 的定義,這種情況下,資源路徑是相對工作目錄而言的。
注意:若位置路徑帶有 classpath 字首或 url 字首,會覆寫預設建立的用于加載 bean 定義的 resource 類型,比如這種情況下的 filesystemxmlapplicationcontext
,實際是從類路徑下加載了 bean 的定義。可是,這個上下文仍然是 filesystemxmlapplicationcontext,而不是 classpathxmlapplicationcontext,在後續作為 resourceloader 來使用時,不帶字首的路徑仍然會從檔案系統中加載。
構造 classpathxmlapplicationcontext 執行個體 – 快捷方式
classpathxmlapplicationcontext 提供了多個構造函數,以利于快捷建立 classpathxmlapplicationcontext 的執行個體。最好莫不過使用隻包含多個 xml 檔案名(不帶路徑資訊)的字元串數組和一個 class 參數的構造器,所省略路徑資訊 classpathxmlapplicationcontext 會從 class 參數 擷取:
下面的這個例子,可以讓你對個構造器有比較清晰的認識。試想一個如下類似的目錄結構:
由 services.xml 和 daos.xml 中 bean 所組成的 classpathxmlapplicationcontext,可以這樣來初始化:
欲要知道 classpathxmlapplicationcontext 更多不同類型的構造器,請查閱 javadocs 文檔。
從前文可知,應用上下文構造器的中的資源路徑可以是單一的路徑(即一對一地映射到目标資源);另外資源路徑也可以使用高效的通配符——可包含 classpath*:字首 或 ant 風格的正規表達式(使用 spring 的 pathmatcher 來比對)。
通配符機制的其中一種應用可以用來組裝元件式的應用程式。應用程式裡所有元件都可以在一個共知的位置路徑釋出自定義的上下文片段,則最終應用上下文可使用 classpath*: 在同一路徑字首(前面的共知路徑)下建立,這時所有元件上下文的片段都會被自動組裝。
謹記,路徑中的通配符特定用于應用上下文的構造器,隻會在應用構造時有效,與其 resource 自身類型沒有任何關系。不可以使用 classpth*:來構造任一真實的 resource,因為一個資源點一次隻可以指向一個資源。(如果直接使用 pathmatcher 的工具類,也可以在路徑中使用通配符)
以下是一些使用了 ant 風格的位置路徑:
當位置路徑使用了 ant 風格,解釋器會遵循一套複雜且預定義的邏輯來解釋這些位置路徑。解釋器會先從位置路徑裡擷取最靠前的不帶通配符的路徑片段,使用這個路徑片段來建立一個 resource ,并從 resource 裡擷取其 url,若所擷取到 url 字首并不是 “jar:”,或其他特殊容器産生的特殊字首(如 weblogic 的 zip:,websphere wsjar),則從 resource 裡擷取 java.io.file 對象,并通過其周遊檔案系統。進而解決位置路徑裡通配符;若擷取的是 “jar:”的 url ,解析器會從其擷取一個 java.net.jarurlconnection 或手動解析此 url,并周遊 jar 檔案的内容進而解決位置路徑的通配符。
如果指定的路徑已經是檔案url(顯式地或隐含地,因為基本的resourceloader是一個檔案系統的,那麼通配符将保證以完全可移植的方式工作。
如果指定的路徑是類路徑位置,則解析器必須通過classloader.getresource()調用擷取最後一個非通配符路徑段url。 由于這隻是路徑的一個節點(而不是最後的檔案),在這種情況下,它實際上是未定義的(在classloader javadocs中)傳回的是什麼樣的url。 實際上,它始終是一個java.io.file,它表示類路徑資源解析為檔案系統位置的目錄或某種類型的jar url,其中類路徑資源解析為一個jar位置。 盡管如此,這種操作仍然存在可移植性問題。
如果為最後一個非通配符段擷取了一個jar url,解析器必須能夠從中擷取java.net.jarurlconnection,或者手動解析jar url,以便能夠周遊該jar的内容,然後解析 通配符。 這将在大多數環境中正常工作,但在其他環境中将會失敗,并且強烈建議您在依賴它之前,徹底地在您的特定環境中徹底測試來自jar的資源的通配符解析。
當構造基于 xml 檔案的應用上下文時,位置路徑可以使用 classpath*:字首:
classpath*:的使用表示類路徑下所有比對檔案名稱的資源都會被擷取(本質上就是調用了 classloader.getresources(…) 方法),接着将擷取到的資源組裝成最終的應用上下文。
通配符路徑依賴了底層 classloader 的 getresource 方法。可是現在大多數應用伺服器提供了自身的 classloader 實作,其處理 jar 檔案的形式可能各有不同。要在指定伺服器測試 classpath*: 是否有效,簡單點可以使用 getclass().getclassloader().getresources(“”) 去加載類路徑 jar包裡的一個檔案。嘗試在兩個不同的路徑加載名稱相同的檔案,如果傳回的結果不一緻,就需要檢視一下此伺服器中與 classloader 行為設定相關的文檔。
在位置路徑的其餘部分,classpath*: 字首可以與 pathmatcher 結合使用,如:” classpath*:meta-inf/*-beans.xml”。這種情況的解析政策非常簡單:取位置路徑最靠前的無通配符片段,調用 classloader.getresources() 擷取所有比對的類層次加載器可加載的的資源,随後将 pathmacher 的政策應用于每一個獲得的資源(起過濾作用)。
除非所有目标資源都存于檔案系統,否則classpath*:和 ant 風格模式的結合使用,都隻能在至少有一個确定根包路徑的情況下,才能達到預期的效果。換句話說,就是像 classpath*:*.xml 這樣的 pattern 不能從根目錄的 jar 檔案中擷取資源,隻能從根目錄的擴充目錄擷取資源。此問題的造成源于 jdk classloader.getresources() 方法的局限性——當向 classloader.getresources() 傳入空串時(表示搜尋潛在的根目錄),隻能擷取的檔案系統的檔案位置路徑,即擷取不了 jar 中檔案的位置路徑。
如果在多個類路徑上存在所搜尋的根包,那使用 classpath: 和 ant 風格模式一起指定的資源不保證找到比對的資源。因為使用如下的 pattern classpath:com/mycompany/**/service-context.xml
去搜尋隻在某一個路徑存在的指定資源com/mycompany/package1/service-context.xml
時,解析器隻會對 getresource(“com/mycompany”) 傳回的(第一個) url 進行周遊和解釋,則當在多個類路徑存在基礎包節點 “com/mycompany” 時(如在多個 jar 存在這個基礎節點),解析器就不一定會找到指定資源。是以,這種情況下建議結合使用 classpath*: 和 ant 風格模式,classpath*:會讓解析器去搜尋所有包含基礎包節點的類路徑。
filesystemresource 沒有依附 filesystemapplicationcontext,因為 filesystemapplicationcontext 并不是一個真正的 `resourceloader。filesystemresource 并沒有按約定規則來處理絕對和相對路徑。相對路徑是相對與目前工作而言,而絕對路徑則是相對檔案系統的根目錄而言。
然而為了向後相容,當 filesystemapplicationcontext 是一個 resourceloader 執行個體時,我們做了一些改變 —— 不管 filesystemresource` 執行個體的位置路徑是否以 / 開頭, filesystemapplicationcontext 都強制将其作為相對路徑來處理。事實上,這意味着以下例子等效:
還有:(即使它們的意義不一樣 —— 一個是相對路徑,另一個是絕對路徑。)
實踐中,如果确實需要使用絕對路徑,建議放棄 filesystemresource / filesystemxmlapplicationcontext 在絕對路勁的使用,而強制使用 file: 的 urlresource。