Spring Resource和策略模式應用

Spring 把所有能記錄信息的載體,如各種類型的文件、二進制流等都稱爲資源,對 Spring 開發者來說,最常用的資源就是 Spring 配置文件(通常是一份 XML 格式的文件)。

在 Sun 所提供的標準 API 裏,資源訪問通常由 java.net.URL 和文件 IO 來完成,尤其是當我們需要訪問來自網絡的資源時,通常會選擇 URL 類。

URL 類可以處理一些常規的資源訪問問題,但依然不能很好地滿足所有底層資源訪問的需要,比如,暫時還無法從類加載路徑、或相對於 ServletContext 的路徑來訪問資源,雖然 Java 允許使用特定的 URL 前綴註冊新的處理類(例如已有的 http: 前綴的處理類),但是這樣做通常比較複雜,而且 URL 接口還缺少一些有用的功能,比如檢查所指向的資源是否存在等。

Spring 改進了 Java 資源訪問的策略。Spring 爲資源訪問提供了一個 Resource 接口,該接口提供了更強的資源訪問能力,Spring 框架本身大量使用了 Resource 接口來訪問底層資源。

Resource 接口是具體資源訪問策略的抽象,也是所有資源訪問類所實現的接口。Resource 接口主要提供瞭如下幾個方法:

  • getInputStream ():定位並打開資源,返回資源對應的輸入流。每次調用都返回新的輸入流。調用者必須負責關閉輸入流。
  • exists ():返回 Resource 所指向的資源是否存在。
  • isOpen ():返回資源文件是否打開,如果資源文件不能多次讀取,每次讀取結束應該顯式關閉,以防止資源泄漏。
  • getDescription ():返回資源的描述信息,通常用於資源處理出錯時輸出該信息,通常是全限定文件名或實際 URL。
  • getFile:返回資源對應的 File 對象。
  • getURL:返回資源對應的 URL 對象。

Resource 和策略模式 Resource 接口就是策略模式的典型應用,Resource 接口就代表資源訪問策略,但具體採用哪種策略實現,Resource 接口並不理會。客戶端程序只和 Resource 接口耦合,並不知道底層採用何種資源訪問策略,這樣應用可以在不同的資源訪問策略之間自由切換。

最後兩個方法通常無須使用,僅在通過簡單方式訪問無法實現時,Resource 提供傳統的資源訪問的功能。

Resource 接口本身沒有提供訪問任何底層資源的實現邏輯,針對不同的底層資源,Spring 將會提供不同的 Resource 實現類,不同的實現類負責不同的資源訪問邏輯。

Resource 不僅可在 Spring 的項目中使用,也可直接作爲資源訪問的工具類使用。意思是說:即使不使用 Spring 框架,也可以使用 Resource 作爲工具類,用來代替 URL。當然,使用 Resource 接口會讓代碼與 Spring 的接口耦合在一起,但這種耦合只是部分工具集的耦合,不會造成太大的代碼污染。

Resource 的實現類

Resource 接口是 Spring 資源訪問策略的抽象,它本身並不提供任何資源訪問實現,具體的資源訪問由該接口的實現類完成 —— 每個實現類代表一種資源訪問策略。

Spring 爲 Resource 接口提供瞭如下實現類:

  • UrlResource:訪問網絡資源的實現類。
  • ClassPathResource:訪問類加載路徑裏資源的實現類。
  • FileSystemResource:訪問文件系統裏資源的實現類。
  • ServletContextResource:訪問相對於 ServletContext 路徑裏的資源的實現類:
  • InputStreamResource:訪問輸入流資源的實現類。
  • ByteArrayResource:訪問字節數組資源的實現類。

這些 Resource 實現類,針對不同的的底層資源,提供了相應的資源訪問邏輯,並提供便捷的包裝,以利於客戶端程序的資源訪問。

使用 UrlResource 訪問網絡資源

訪問網絡資源通過 UrlResource 類實現,UrlResource 是 java.net.URL 類的包裝,主要用於訪問之前通過 URL 類訪問的資源對象。URL 資源通常應該提供標準的協議前綴。例如:file: 用於訪問文件系統;http: 用於通過 HTTP 協議訪問資源;ftp: 用於通過 FTP 協議訪問資源等。

UrlResource 類實現 Resource 接口,對 Resource 全部方法提供了實現,完全支持 Resource 的全部 API。下面代碼示範了使用 UrlResource 訪問文件系統資源的示例。程序如下:

清單 1. UrlResourceTest.java
public class UrlResourceTest 
{ 
public static void main(String[] args) throws Exception 
{ 
// 創建一個 Resource 對象,指定從文件系統裏讀取資源
UrlResource ur = new UrlResource("file:book.xml");
// 獲取該資源的簡單信息
System.out.println(ur.getFilename()); 
System.out.println(ur.getDescription()); 
// 創建 Dom4j 的解析器
SAXReader reader = new SAXReader(); 
Document doc = reader.read(ur.getFile()); 
// 獲取根元素
Element el = doc.getRootElement(); 
List l = el.elements(); 
// 此處省略了訪問、輸出 XML 文檔內容的代碼。
... 
} 
}

上面程序中粗體字代碼使用 UrlResource 來訪問本地磁盤資源,雖然 UrlResource 是爲訪問網絡資源而設計的,但通過使用 file 前綴也可訪問本地磁盤資源。如果需要訪問網絡資源,可以使用如下兩個常用前綴:

  • http:-該前綴用於訪問基於 HTTP 協議的網絡資源。
  • ftp:-該前綴用於訪問基於 FTP 協議的網絡資源。

由於 UrlResource 是對 java.net.URL 的封裝,所以 UrlResource 支持的前綴與 URL 類所支持的前綴完全相同。

將應用所需的 book.xml 訪問放在應用的當前路徑,運行該程序,即可看到使用 UrlResource 訪問本地磁盤資源的效果。

使用 ClassPathResource 訪問類加載路徑下的資源。

ClassPathResource 用來訪問類加載路徑下的資源,相對於其他的 Resource 實現類,其主要優勢是方便訪問類加載路徑裏的資源,尤其對於 Web 應用,ClassPathResource 可自動搜索位於 WEB-INF/classes 下的資源文件,無須使用絕對路徑訪問。

下面示例程序示範了將 book.xml 放在類加載路徑下,然後使用如下程序訪問它:

清單 2. ClassPathResourceTest.java
public class ClassPathResourceTest 
{ 
public static void main(String[] args) throws Exception 
{ 
      // 創建一個 Resource 對象,從類加載路徑裏讀取資源
      ClassPathResource cr = new ClassPathResource("book.xml");
      // 獲取該資源的簡單信息
      System.out.println(cr.getFilename()); 
      System.out.println(cr.getDescription()); 
      // 創建 Dom4j 的解析器
      SAXReader reader = new SAXReader(); 
      Document doc = reader.read(cr.getFile()); 
      // 獲取根元素
      Element el = doc.getRootElement(); 
      List l = el.elements(); 
      // 此處省略了訪問、輸出 XML 文檔內容的代碼。
      ... 
} 
}

上面程序的粗體字代碼用於訪問類加載路徑下的 book.xml 文件,對比前面進行資源訪問的 2 個示例程序,我們發現兩個程序除了進行資源訪問的代碼有所區別之外,其他程序代碼基本一致,這就是 Spring 資源訪問的優勢:Spring 的資源訪問消除了底層資源訪問的差異,允許程序以一致的方式來訪問不同的底層資源。

ClassPathResource 實例可使用 ClassPathResource 構造器顯式地創建,但更多的時候它都是隱式創建的,當執行 Spring 的某個方法時,該方法接受一個代表資源路徑的字符串參數,當 Spring 識別該字符串參數中包含 classpath: 前綴後,系統將會自動創建 ClassPathResource 對象。

使用 FileSystemResource 訪問文件系統資源

Spring 提供的 FileSystemResource 類用於訪問文件系統資源,使用 FileSystemResource 來訪問文件系統資源並沒有太大的優勢,因爲 Java 提供的 File 類也可用於訪問文件系統資源。

當然使用 FileSystemResource 也可消除底層資源訪問的差異,程序通過統一的 Resource API 來進行資源訪問。下面程序是使用 FileSystemResource 來訪問文件系統資源的示例程序。

清單 3. FileSystemResourceTest.java
public class FileSystemResourceTest 
{ 
public static void main(String[] args) throws Exception 
{ 
// 默認從文件系統的當前路徑加載 book.xml 資源
FileSystemResource fr = new FileSystemResource("book.xml"); 
// 獲取該資源的簡單信息
System.out.println(fr.getFilename()); 
System.out.println(fr.getDescription()); 
// 創建 Dom4j 的解析器
SAXReader reader = new SAXReader(); 
Document doc = reader.read(fr.getFile()); 
// 獲取根元素
Element el = doc.getRootElement(); 
List l = el.elements(); 
// 此處省略了訪問、輸出 XML 文檔內容的代碼。
... 
} 
}

與前兩種 Resource 作資源訪問的區別在於:資源字符串確定的資源,位於本地文件系統內 ,而且無須使用任何前綴。

FileSystemResource 實例可使用 FileSystemResource 構造器顯式地創建。但更多的時候它都是隱式創建的,執行 Spring 的某個方法時,該方法接受一個代表資源路徑的字符串參數,當 Spring 識別該字符串參數中包含 file: 前綴後,系統將會自動創建 FileSystemResource 對象。

通過上面代碼不難發現,程序使用 UrlResource、FileSystemResource、ClassPathResource 三個實現類來訪問資源的代碼差異並不大,唯一的缺點在於客戶端代碼需要與 Resource 接口的實現類耦合,這依然無法實現高層次解耦。

這對於策略模式來說將沒有任何問題,策略模式要解決的就是這個問題,策略模式將會提供一個 Context 類來爲客戶端代碼 “智能” 地選擇策略實現類。至此我們發現了 Spring 資源訪問的兩個重要部分:Resource 接口和多個實現類,它們之間有如圖 1 所示

圖 1.Spring 資源訪問的策略接口和策略實現類

圖 1.Spring 資源訪問的策略接口和策略實現類

圖 1 所示的類圖中提供了一個 Resouce 接口,這個接口就是 Spring 爲資源訪問所提供的策略接口,該接口下的大量實現類:UrlResource、ClassPathResource、FileSystemResource、ServletContextResource、ByteArrayResource、InputStreamReource 都實現了該策略接口,用於實現不同的資源訪問策略。

下面我們將通過一個淺顯的示例來講解策略模式:

策略模式

策略模式用於封裝系列的算法,這些算法通常被封裝在一個被稱爲 Context 類中,客戶端程序可以自由選擇其中一種算法,或讓 Context 爲客戶端選擇一個最佳的算法 —— 使用策略模式的優勢是爲了支持算法的自由切換。

考慮如下場景:現在我們正在開發一個網上書店,該書店爲了更好地促銷,經常需要對圖書進行打折促銷,程序需要考慮各種打折促銷的計算方法。

爲了實現書店現在所提供的各種打折需求,程序考慮使用如下方式來實現

// 一段實現 discount () 方法代碼

public double discount(double price) 
{ 
// 針對不同情況採用不同的打折算法
switch(getDiscountType()){case VIP_DISCOUNT:return vipDiscount(price);case OLD_DISCOUNT:return oldDiscount(price);case SALE_DISCOUNT:return saleDiscount(price);...}
}

上面粗體字代碼會根據打折類型來決定使用不同的打折算法,從而滿足該書店促銷打折的要求。從功能實現的角度來看,這段代碼沒有太大的問題。但這段代碼有一個明顯的不足,程序中各種打折方法都被直接寫入了 discount (double price) 方法中。如有一天,該書店需要新增一種打折類型呢?那開發人員必須修改至少三處代碼:首先需要增加一個常量,該常量代表新增的打折類型;其次需要在 switch 語句中增加一個 case 語句;最後開發人員需要實現 xxxDiscount () 方法,用於實現新增的打折算法。

爲了改變這種不好的設計,下面將會選擇使用策略模式來實現該功能,下面先提供一個打折算法的接口,該接口裏包含一個 getDiscount () 方法,該接口代碼如下:

清單 4. DiscountStrategy.java
public interface DiscountStrategy 
{ 
//定義一個用於計算打折價的方法
double getDiscount(double originPrice); 
}

對於程序中這個 DiscountStrategy 接口而言,實現該接口的實現類就可以實現打折,但具體的打折策略與該接口無關,而是由具體的實現類來決定打折策略。由此可見,這個 DiscountStrategy 接口的作用和 Spring 框架中 Resource 接口的作用完全相同。

就像 Spring 框架必須爲 Resource 接口提供大量實現類一樣,我們此處也需要爲 DiscountStrategy 接口提供兩個實現類,每個實現類代表一種打折策略。

下面代表 VIP 打折策略

清單 5. VipDiscount.java
// 實現 DiscountStrategy 接口,實現對 VIP 打折的算法
public class VipDiscount 
implements DiscountStrategy 
{ 
// 重寫 getDiscount() 方法,提供 VIP 打折算法
public double getDiscount(double originPrice) 
{ 
System.out.println("使用 VIP 折扣 ..."); 
return originPrice * 0.5; 
} 
}

下面代表舊書打折策略

清單 6. OldDiscount.java
public class OldDiscount 
implements DiscountStrategy 
{ 
// 重寫 getDiscount() 方法,提供舊書打折算法
public double getDiscount(double originPrice) 
{ 
System.out.println("使用舊書折扣 ..."); 
return originPrice * 0.7; 
} 
}

此時遇到了與前面程序相同的問題,如果客戶端代碼直接與具體的策略類(如 VIPDiscount、OldDiscount)耦合,那客戶端代碼將無法實現解耦。因此策略模式需要爲客戶端代碼提供了一個 Context 類,讓它爲客戶端代碼決定採用哪種策略。例如本示例程序提供一個 DiscountContext 類,該類用於爲客戶端代碼選擇合適折扣策略,當然也允許用戶自由選擇折扣策略。下面是該 DiscountContext 類的代碼:

清單 7. DiscountContext.java
public class DiscountContext 
{ 
// 組合一個 DiscountStrategy 對象
private DiscountStrategy strategy; 
// 構造器,傳入一個 DiscountStrategy 對象
public DiscountContext(DiscountStrategy strategy) 
{ 
this.strategy  = strategy; 
} 
// 根據實際所使用的 DiscountStrategy 對象得到折扣價
public double getDiscountPrice(double price) 
{ 
// 如果 strategy 爲 null,系統自動選擇 OldDiscount 類
if (strategy == null){strategy = new OldDiscount();}return this.strategy.getDiscount(price);
} 
// 提供切換算法的方法
public void changeDiscount(DiscountStrategy strategy) 
{ 
this.strategy = strategy; 
} 
}

從上面程序的粗體字代碼可以看出,該 Context 類扮演了決策者的角色,它決定調用哪個折扣策略來處理圖書打折。當客戶端代碼沒有選擇合適的折扣時,該 Context 會自動選擇 OldDiscount 折扣策略;用戶也可根據需要選擇合適的折扣策略。

下面程序示範了客戶端代碼使用該 Contex 類來處理圖書打折:

清單 8. StrategyTest.java
public class StrategyTest 
{ 
public static void main(String[] args) 
{ 
// 客戶端沒有選擇打折策略類
DiscountContext dc = new DiscountContext(null);
double price1 = 79; 
// 使用默認的打折策略
System.out.println("79 元的書默認打折後的價格是:" 
+ dc.getDiscountPrice(price1)); 
// 客戶端選擇合適的 VIP 打折策略
dc.changeDiscount(new VipDiscount());
double price2 = 89; 
// 使用 VIP 打折得到打折價格
System.out.println("89 元的書對 VIP 用戶的價格是:" 
+ dc.getDiscountPrice(price2)); 
} 
}

上面程序第一行粗體字代碼創建了一個 DiscountContext 對象,客戶端並未指定實際所需的打折策略類,故程序將使用默認的打折策略類;程序第二行粗體字代碼指定使用 VipDiscount 策略類,故程序將改爲使用使用 VIP 打折策略。

再次考慮前面的需求:當業務需要新增一種打折類型時,系統只需要新定義一個 DiscountStrategy 實現類,該實現類實現 getDiscount () 方法,用於實現新的打折算法即可。客戶端程序需要切換爲新的打折策略時,則需要先調用 DiscountContext 的 setDiscount () 方法切換爲新的打折策略。

從上面介紹中可以看出,使用策略模式可以讓客戶端代碼在不同的打折策略之間切換,但也有一個小小的遺憾:客戶端代碼需要和不同的策略類耦合。

爲了彌補這個不足,我們可以考慮使用配置文件來指定 DiscountContext 使用哪種打折策略 —— 這就徹底分離客戶端代碼和具體打折策略 —— 這正好是 Spring 框架的強項,Spring 框架採用配置文件來管理 Bean,當然也可以管理資源。

下面我們再回到 Spring 框架裏,看看 Spring 框架的 Context 如何 “智能” 地選擇資源訪問策略,

ResourceLoader 接口和 ResourceLoaderAware 接口

Spring 提供兩個標誌性接口:

  • ResourceLoader:該接口實現類的實例可以獲得一個 Resource 實例。
  • ResourceLoaderAware:該接口實現類的實例將獲得一個 ResourceLoader 的引用。

在 ResourceLoader 接口裏有如下方法:

  • Resource getResource (String location):該接口僅包含這個方法,該方法用於返回一個 Resource 實例。ApplicationContext 的實現類都實現 ResourceLoader 接口,因此 ApplicationContext 可用於直接獲取 Resource 實例。

策略模式的優勢 當 Spring 應用需要進行資源訪問時,實際上並不需要直接使用 Resource 實現類,而是調用 ApplicationContext 實例的 getResource () 方法來獲得資源,ApplicationContext 將會負責選擇 Resource 的實現類,也就是確定具體的資源訪問策略,從而將應用程序和具體的資源訪問策略分離開來,這就體現了策略模式的優勢。

此處 Spring 框架的 ApplicationContext 不僅是 Spring 容器,而且它還是資源訪問策略的 “決策者”,也就是策略模式中 Context 對象,它將爲客戶端代碼 “智能” 地選擇策略實現。

當 ApplicationContext 實例獲取 Resource 實例時,系統將默認採用與 ApplicationContext 相同的資源訪問策略。對於如下代碼:

// 通過 ApplicationContext 訪問資源

Resource res = ctx.getResource("some/resource/path/myTemplate.txt);

從上面代碼中無法確定 Spring 將哪個實現類來訪問指定資源,Spring 將採用和 ApplicationContext 相同的策略來訪問資源。也就是說:如果 ApplicationContext 是 FileSystemXmlApplicationContext,res 就是 FileSystemResource 實例;如果 ApplicationContext 是 ClassPathXmlApplicationContext,res 就是 ClassPathResource 實例;如果 ApplicationContext 是 XmlWebApplicationContext,res 是 ServletContextResource 實例。

看如下示例程序,下面程序將使用 ApplicationContext 來訪問資源:

清單 9. ResourceAwareTest.java
public class ResourceAwareTest 
{ 
public static void main(String[] args) throws Exception 
{ 
// 創建 ApplicationContext 實例
ApplicationContext ctx = newClassPathXmlApplicationContext("bean.xml");Resource res = ctx.getResource("book.xml");
// 獲取該資源的簡單信息
System.out.println(res.getFilename()); 
System.out.println(res.getDescription()); 
// 創建 Dom4j 的解析器
SAXReader reader = new SAXReader(); 
Document doc = reader.read(res.getFile()); 
// 獲取根元素
Element el = doc.getRootElement(); 
List l = el.elements(); 
// 此處省略了訪問、輸出 XML 文檔內容的代碼。
... 
} 
}

上面程序中第一行粗體字創建了一個 ApplictionContext 對象,第二行粗體字代碼通過該對象來獲取資源,由於程序中使用了 ClassPathApplicationContext 來獲取資源,所以 Spring 將會從類加載路徑下來訪問資源,也就是使用 ClassPathResource 實現類。

另一方面使用 ApplicationContext 來訪問資源時,也可不理會 ApplicationContext 的實現類,強制使用指定的 ClassPathResource、FileSystemResource 等實現類,這可通過不同前綴來指定,如下代碼所示:

// 通過 classpath: 前綴,強制使用 ClassPathResource ``Resource r = ctx.getResource("classpath:bean.xml”);

類似地,還可以使用標準的 java.net.URL 前綴來強制使用 UrlResource,如下所示:

// 通過標準 file: 前綴,強制使用 UrlResource 訪問本地文件資源``Resource r = ctx.getResource("file:bean.xml); ``// 通過標準 http: 前綴,強制使用 UrlResource 基於 HTTP 協議的網絡資源``Resource r = ctx.getResource("http://localhost:8888/bean.xml);

以下是常見前綴及對應的訪問策略:

  • classpath: 以 ClassPathResource 實例來訪問類路徑裏的資源。
  • file: 以 UrlResource 實例訪問本地文件系統的資源。
  • http: 以 UrlResource 實例訪問基於 HTTP 協議的網絡資源。
  • 無前綴:由於 ApplicationContext 的實現類來決定訪問策略。

ResourceLoaderAware 接口則用於指定該接口的實現類必須持有一個 ResourceLoader 實例。

類似於 Spring 提供的 BeanFactoryAware、BeanNameAware 接口,ResourceLoaderAware 接口也提供了一個 setResourceLoader () 方法,該方法將由 Spring 容器負責調用,Spring 容器會將一個 ResourceLoader 對象作爲該方法的參數傳入。

當我們把將 ResourceLoaderAware 實例部署在 Spring 容器中後,Spring 容器會將自身當成 ResourceLoader 作爲 setResourceLoader () 方法的參數傳入,由於 ApplicationContext 的實現類都實現了 ResourceLoader 接口,Spring 容器自身完全可作爲 ResourceLoader 使用。

使用 Resource 作爲屬性

前面介紹了 Spring 提供的資源訪問策略,但這些依賴訪問策略要麼需要使用 Resource 實現類,要麼需要使用 ApplicationContext 來獲取資源。實際上,當應用程序中的 Bean 實例需要訪問資源時,Spring 有更好的解決方法:直接利用依賴注入。

從這個意義上來看,Spring 框架不僅充分利用了策略模式來簡化資源訪問,而且還將策略模式和 IoC 進行充分地結合,最大程度地簡化了 Spring 資源訪問。

歸納起來,如果 Bean 實例需要訪問資源,有如下兩種解決方案:

  • 代碼中獲取 Resource 實例。
  • 使用依賴注入。

對於第一種方式的資源訪問,當程序獲取 Resource 實例時,總需要提供 Resource 所在的位置,不管通過 FileSystemResource 創建實例,還是通過 ClassPathResource 創建實例,或者通過 ApplicationContext 的 getResource () 方法獲取實例,都需要提供資源位置。這意味着:資源所在的物理位置將被耦合到代碼中,如果資源位置發生改變,則必須改寫程序。因此,通常建議採用第二種方法,讓 Spring 爲 Bean 實例依賴注入資源。

看如下 TestBean,它有一個 Resource 類型的 res Field,程序併爲該 Field 提供了對應的 setter 方法,這就可以利用 Spring 的依賴注入了。

清單 9. TestBean.java
public class TestBean 
{ 
  private Resource res;
  // 依賴注入 Resource 資源的 setter 方法
  public void setResource(Resource res){this.res = res;}
  public void parse()throws Exception 
  { 
      // 獲取該資源的簡單信息
      System.out.println(res.getFilename()); 
      System.out.println(res.getDescription()); 
      // 創建 Dom4j 的解析器
      SAXReader reader = new SAXReader(); 
      Document doc = reader.read(res.getFile()); 
      // 獲取根元素
      Element el = doc.getRootElement(); 
      List l = el.elements(); 
      // 此處省略了訪問、輸出 XML 文檔內容的代碼。
      ... 
  } 
}

上面程序中粗體字代碼定義了一個 Resource 類型的 res 屬性,該屬性需要可以接受 Spring 的依賴注入。除此之外,程序中的 parse () 方法用於解析 res 資源所代表的 XML 文件。

在容器中配置該 Bean,併爲該 Bean 指定資源文件的位置,配置文件如下:

清單 10. bean.xml
<?xml version="1.0" encoding="GBK"?> 
 <!-- 指定 Spring 配置文件的 DTD 信息 -->
 <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN"
"http://www.springframework.org/dtd/spring-beans-2.0.dtd"> 
 <!-- Spring 配置文件的根元素 -->
 <beans> 
 <bean id="test" class="lee.TestBean"> 
 <!-- 注入資源 -->
 <property name="resource"value="classpath:book.xml"/>
 </bean> 
 </beans>

上面配置文件中粗體字代碼配置了資源的位置,並使用了 classpath: 前綴,這指明讓 Spring 從類加載路徑里加載 book.xml 文件。與前面類似的是,此處的前綴也可採用 http:、ftp: 等,這些前綴將強制 Spring 採用怎樣的資源訪問策略(也就是指定具體使用哪個 Resource 實現類);如果不採用任何前綴,則 Spring 將採用與該 ApplicationContext 相同的資源訪問策略來訪問資源。

採用依賴注入,允許動態配置資源文件位置,無須將資源文件位置寫在代碼中,當資源文件位置發生變化時,無須改寫程序,直接修改配置文件即可。

小結

現在,Spring 框架已成爲絕大部分框架都爭相 “擁抱” 的對象(現在大部分 Java EE 框架都會提供與 Spring 整合的接口),Spring 框架能發展到今天絕非偶然,很大程度上來自於兩方面原因:一方面 Spring 框架既提供了簡單、易用的編程接口,因此深得用戶擁護;另一方面 Spring 框架自身具有極爲優秀的設計,這種優秀的設計保證了 Spring 框架具有強大生命力。對於一個有志於向架構師發展的軟件工程師而言,精研 Spring 框架的源碼,深入理解 Spring 框架的設計是一個不錯的途徑。本文主要從策略模式的角度來分析了 Spring 資源訪問方面的設計,從而幫助讀者更好地理解 Spring 框架。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章