設計模式_策略模式_在Spring中的應用


一.理論


 

在spring中經常有讀取配置文件的需求,這里就會用到一個Spring提供的Resource接口

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

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

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

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

Spring 為 Resource 接口提供了如下實現類:

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

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

 

 

二.源碼


 

這里跟蹤ClassPathXmlApplicationContext對象的創建,來了解Spring底層怎么使用Resource接口及其實現類達成策略模式

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

1 //1.根據傳入的配置文件地址,創建容器對象  ClassPathXmlApplicationContext
2 public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
3     this(new String[] {configLocation}, true, null);
4 }

 

 1 //2.1中代碼調用到此處,此處調用父類構造函數  ClassPathXmlApplicationContext
 2 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
 3             throws BeansException {
 4 
 5     super(parent);
 6     setConfigLocations(configLocations);
 7     if (refresh) {
 8         refresh();
 9     }
10 }

 

1 //3.2中代碼一步步調用到此處  AbstractApplicationContext
2 public AbstractApplicationContext(ApplicationContext parent) {
3     this();
4     setParent(parent);
5 }

 

1 //4.3中代碼調用此處  AbstractApplicationContext
2 public AbstractApplicationContext() {
3     this.resourcePatternResolver = getResourcePatternResolver();
4 }

 

1 //5.返回能將1中傳入的configLocation轉換成Resource對象的ResourcePatternResolver  AbstractApplicationContext
2 protected ResourcePatternResolver getResourcePatternResolver() {
3     return new PathMatchingResourcePatternResolver(this);
4 }

 

 1 //6.真正用到策略模式的地方,根據location的內容,決定返回對應的Resource實現,這個過程對客戶來說是透明的  DefaultResourceLoader
 2 @Override
 3 public Resource getResource(String location) {
 4     Assert.notNull(location, "Location must not be null");
 5 
 6     for (ProtocolResolver protocolResolver : this.protocolResolvers) {
 7         Resource resource = protocolResolver.resolve(location, this);
 8         if (resource != null) {
 9             return resource;
10         }
11     }
12 
13     if (location.startsWith("/")) {
14         return getResourceByPath(location);
15     }
16     else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
17         return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
18     }
19     else {
20         try {
21             // Try to parse the location as a URL...
22             URL url = new URL(location);
23             return new UrlResource(url);
24         }
25         catch (MalformedURLException ex) {
26             // No URL -> resolve as resource path.
27             return getResourceByPath(location);
28         }
29     }
30 }

 

參考:https://www.ibm.com/developerworks/cn/java/j-lo-spring-resource/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM