1. 程式人生 > >spring mvc 在Web.xml中自動掃描Spring的配置檔案及resource時classpath*:與classpath:的區別

spring mvc 在Web.xml中自動掃描Spring的配置檔案及resource時classpath*:與classpath:的區別

首先在web.xml中配置監聽器listener,讓spring進行自動獲取。具體加入的程式碼如下:

  1. <listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
只要其啟動服務這個配置就會預設的去載入我們的配置檔案,自動的將裡面的bean都給初始化了。預設情況下它會去/WEB-INF/applicationContext.xml檔案。如果自己想要將配置檔案放到classpath下,即src目錄下,則需要再進行路徑的指定,具體程式碼如下:

  1. <!-- Context Configuration locations for Spring XML files -->
  2. <context-param><param-name>contextConfigLocation</param-name>
  3. <!-- <param-value>/WEB-INF/applicationContext-*.xml,classpath*:applicationContext-*.xml</param-value> -->
  4. <!-- 加入你的配置檔案放在了src下的,命名規則為:applicationContext-*.xml形式,則可以從以下方式配置-->
  5. <param-value>classpath:applicationContext-*.xml</param-value>
  6. </context-param>

這樣的話,在伺服器啟動的時候就會自動的去classpa也就是src目錄下找所有的以:applicationContext-*.xml檔案並將它們初始化。

Spring可以通過指定classpath*:與classpath:字首加路徑的方式從classpath載入檔案,如bean的定義檔案.classpath*:的出現是為了從多個jar檔案中載入相同的檔案.classpath:只能載入找到的第一個檔案.

比如 resource1.jar中的package 'com.test.rs' 有一個 'jarAppcontext.xml' 檔案,內容如下:

<bean name="ProcessorImplA" class="com.test.spring.di.ProcessorImplA" />

resource2.jar中的package 'com.test.rs' 也有一個 'jarAppcontext.xml' 檔案,內容如下:

<bean id="ProcessorImplB" class="com.test.spring.di.ProcessorImplB" />

通過使用下面的程式碼則可以將兩個jar包中的檔案都載入進來

ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath*:com/test/rs/jarAppcontext.xml");

而如果寫成下面的程式碼,就只能找到其中的一個xml檔案(順序取決於jar包的載入順序)

ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath:com/test/rs/jarAppcontext.xml");

classpath*:的使用是為了多個component(最終釋出成不同的jar包)並行開發,各自的bean定義檔案按照一定的規則:package+filename,而使用這些component的呼叫者可以把這些檔案都載入進來.

classpath*:的載入使用了classloader的 getResources() 方法,如果是在不同的J2EE伺服器上執行,由於應用伺服器提供自己的classloader實現,它們在處理jar檔案時的行為也許會有所不同。 要測試classpath*: 是否有效,可以用classloader從classpath中的jar檔案里加載檔案來進行測試:getClass().getClassLoader().getResources("<someFileInsideTheJar>")。(上面的例子是在sun的jre中執行的狀態)

 從Spring的原始碼,在PathMatchingResourcePatternResolver類中,我們可以更清楚的瞭解其對的處理:如果是以classpath*開頭,它會遍歷classpath.

  1. protected Resource[] findAllClassPathResources(String location) throws IOException {  
  2.     String path = location;  
  3.     if (path.startsWith("/")) {  
  4.         path = path.substring(1);  
  5.     }  
  6.     Enumeration resourceUrls = getClassLoader().getResources(path);  
  7.     Set<Resource> result = new LinkedHashSet<Resource>(16);  
  8.     while (resourceUrls.hasMoreElements()) {  
  9.         URL url = (URL) resourceUrls.nextElement();  
  10.         result.add(convertClassLoaderURL(url));  
  11.     }  
  12.     return result.toArray(new Resource[result.size()]);  
  13. }  

http://blog.csdn.net/kkdelta/article/details/5560210,簡介了在JAVA裡遍歷classpath中讀取找到的所有符合名稱的檔案.

另外在載入resource的時候,其他字首的意義如下表所示:注意classpath*只能用與指定配置檔案的路徑,不能用在用於getResource的引數.如appContext.getResource("classpath*:conf/bfactoryCtx.xml")會異常的.

字首 例子 說明

classpath:

classpath:com/myapp/config.xml

從classpath中載入。

file:

file:/data/config.xml

作為 URL 從檔案系統中載入。

http:

http://myserver/logo.png

作為 URL 載入。

(none)

/data/config.xml

根據 ApplicationContext 進行判斷。

從Spring的原始碼可以看出原因:如果是classpath:開頭,從classpath載入,否則嘗試URL,如果失敗,呼叫 getResourceByPath
  1. public Resource getResource(String location) {  
  2.         Assert.notNull(location, "Location must not be null");  
  3.         if (location.startsWith(CLASSPATH_URL_PREFIX)) {  
  4.             returnnew ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());  
  5.         }  
  6.         else {  
  7.             try {  
  8.                 // Try to parse the location as a URL...
  9.                 URL url = new URL(location);  
  10.                 returnnew UrlResource(url);  
  11.             }  
  12.             catch (MalformedURLException ex) {  
  13.                 // No URL -> resolve as resource path.
  14.                 return getResourceByPath(location);  
  15.             }  
  16.         }  
  17.     }  

getResourceByPath會被不同ApplicationContext 實現覆蓋.

如 GenericWebApplicationContext覆蓋為如下:

  1. protected Resource getResourceByPath(String path) {  
  2.         returnnew ServletContextResource(this.servletContext, path);  
  3.     }  
  4. 如 FileSystemXmlApplicationContext覆蓋為如下:  
  5. protected Resource getResourceByPath(String path) {  
  6.         if (path != null && path.startsWith("/")) {  
  7.             path = path.substring(1);  
  8.         }  
  9.         returnnew FileSystemResource(path);  
  10.     }  

最終從檔案載入的時候仍然是JAVA中常見的讀取檔案的方法:

如ClassPathResource得到inputstream的方法是利用class loader.

  1. public InputStream getInputStream() throws IOException {  
  2.     InputStream is;  
  3.     if (this.clazz != null) {  
  4.         is = this.clazz.getResourceAsStream(this.path);  
  5.     }  

如FileSystemResource得到inputstream的方法是利用FileInputStream.

    public InputStream getInputStream() throws IOException {
        return new FileInputStream(this.file);
    }

如ServletContextResource得到inputstream的方法是利用servletContext.getResourceAsStream.

  1. public InputStream getInputStream() throws IOException {  
  2.     InputStream is = this.servletContext.getResourceAsStream(this.path);  
  3.     if (is == null) {  
  4.         thrownew FileNotFoundException("Could not open " + getDescription());  
  5.     }  
  6.     return is;  
  7. }