读书人

Spring加载resource时classpath*与cla

发布时间: 2012-10-27 10:42:26 作者: rapoo

Spring加载resource时classpath*:与classpath:的区别

Spring可以通过指定classpath*:与classpath:前缀加路径的方式从classpath加载文件,如bean的定义文件.classpath*:的出现是为了从多个jar文件中加载相同的文件.classpath:只能加载找到的第一个文件.

比如 resource1.jar中的package 'com.test.rs' 有一个 'jarAppcontext.xml' 文件,内容如下:

<bean name="ProcessorImplA" />

resource2.jar中的package 'com.test.rs' 也有一个 'jarAppcontext.xml' 文件,内容如下:

<bean id="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的?[java]?view plaincopy

  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:

[java]?view plaincopy

  1. public?Resource?getResource(String?location)?{??
  2. ????????Assert.notNull(location,?"Location?must?not?be?null");??
  3. ????????if?(location.startsWith(CLASSPATH_URL_PREFIX))?{??
  4. ????????????return?new?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. ????????????????return?new?UrlResource(url);??
  11. ????????????}??
  12. ????????????catch?(MalformedURLException?ex)?{??
  13. ????????????????//?No?URL?->?resolve?as?resource?path.??
  14. ????????????????return?getResourceByPath(location);??
  15. ????????????}??
  16. ????????}??
  17. ????}??


getResourceByPath会被不同ApplicationContext?实现覆盖.

如 GenericWebApplicationContext覆盖为如下:

[java]?view plaincopy
  1. protected?Resource?getResourceByPath(String?path)?{??
  2. ????????return?new?ServletContextResource(this.servletContext,?path);??
  3. ????}??
  4. ??
  5. 如?FileSystemXmlApplicationContext覆盖为如下:??
  6. ??
  7. protected?Resource?getResourceByPath(String?path)?{??
  8. ????????if?(path?!=?null?&&?path.startsWith("/"))?{??
  9. ????????????path?=?path.substring(1);??
  10. ????????}??
  11. ????????return?new?FileSystemResource(path);??
  12. ????}??

最终从文件加载的时候仍然是JAVA中常见的读取文件的方法:

?

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

[java]?view plaincopy
  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.

[java]?view plaincopy
  1. public?InputStream?getInputStream()?throws?IOException?{??
  2. ????InputStream?is?=?this.servletContext.getResourceAsStream(this.path);??
  3. ????if?(is?==?null)?{??
  4. ????????throw?new?FileNotFoundException("Could?not?open?"?+?getDescription());??
  5. ????}??
  6. ????return?is;??
  7. }??

?