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.
- protected?Resource[]?findAllClassPathResources(String?location)?throws?IOException?{??
- ????String?path?=?location;??
- ????if?(path.startsWith("/"))?{??
- ????????path?=?path.substring(1);??
- ????}??
- ????Enumeration?resourceUrls?=?getClassLoader().getResources(path);??
- ????Set<Resource>?result?=?new?LinkedHashSet<Resource>(16);??
- ????while?(resourceUrls.hasMoreElements())?{??
- ????????URL?url?=?(URL)?resourceUrls.nextElement();??
- ????????result.add(convertClassLoaderURL(url));??
- ????}??
- ????return?result.toArray(new?Resource[result.size()]);??
- }??
http://blog.csdn.net/kkdelta/article/details/5560210,簡介了在JAVA里遍歷classpath中讀取找到的所有符合名稱的文件.
另外在加載resource的時候,其他前綴的意義如下表所示:注意classpath*只能用與指定配置文件的路徑,不能用在用于 getResource的參數.如 appContext.getResource("classpath*:conf/bfactoryCtx.xml")會異常的.
前綴 | 例子 | 說明 |
---|---|---|
classpath: |
| 從classpath中加載。 |
file: |
| |
http: |
| 作為 |
(none) |
| 根據 |
從Spring的源碼可以看出原因:如果是classpath:開頭,從classpath加載,否則嘗試URL,如果失敗,調用 getResourceByPath
- public?Resource?getResource(String?location)?{??
- ????????Assert.notNull(location,?"Location?must?not?be?null");??
- ????????if?(location.startsWith(CLASSPATH_URL_PREFIX))?{??
- ????????????return?new?ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()),?getClassLoader());??
- ????????}??
- ????????else?{??
- ????????????try?{??
- ????????????????//?Try?to?parse?the?location?as?a?URL...??
- ????????????????URL?url?=?new?URL(location);??
- ????????????????return?new?UrlResource(url);??
- ????????????}??
- ????????????catch?(MalformedURLException?ex)?{??
- ????????????????//?No?URL?->?resolve?as?resource?path.??
- ????????????????return?getResourceByPath(location);??
- ????????????}??
- ????????}??
- ????}??
getResourceByPath會被不同ApplicationContext
實現覆蓋.
如 GenericWebApplicationContext覆蓋為如下:
- protected?Resource?getResourceByPath(String?path)?{??
- ????????return?new?ServletContextResource(this.servletContext,?path);??
- ????}??
- ??
- 如?FileSystemXmlApplicationContext覆蓋為如下:??
- ??
- protected?Resource?getResourceByPath(String?path)?{??
- ????????if?(path?!=?null?&&?path.startsWith("/"))?{??
- ????????????path?=?path.substring(1);??
- ????????}??
- ????????return?new?FileSystemResource(path);??
- ????}??
最終從文件加載的時候仍然是JAVA中常見的讀取文件的方法:
如ClassPathResource得到inputstream的方法是利用class loader.
- public?InputStream?getInputStream()?throws?IOException?{??
- ????InputStream?is;??
- ????if?(this.clazz?!=?null)?{??
- ????????is?=?this.clazz.getResourceAsStream(this.path);??
- ????}??
如FileSystemResource得到inputstream的方法是利用FileInputStream.
??? public InputStream getInputStream() throws IOException {
?? ??? ?return new FileInputStream(this.file);
?? ?}
如ServletContextResource得到inputstream的方法是利用servletContext.getResourceAsStream.
- public?InputStream?getInputStream()?throws?IOException?{??
- ????InputStream?is?=?this.servletContext.getResourceAsStream(this.path);??
- ????if?(is?==?null)?{??
- ????????throw?new?FileNotFoundException("Could?not?open?"?+?getDescription());??
- ????}??
- ????return?is;??
- }?