Spring加载resource,classpath*:与classpath

2024-05-09 16:18

本文主要是介绍Spring加载resource,classpath*:与classpath,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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()]); 
<span style="background-color: rgb(255, 255, 255);">    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()]);}</span>

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.     } 
<span style="background-color: rgb(255, 255, 255);">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);}}}</span>

getResourceByPath会被不同ApplicationContext 实现覆盖.

如 GenericWebApplicationContext覆盖为如下:

  1. protected Resource getResourceByPath(String path) { 
  2.         returnnew 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.         returnnew FileSystemResource(path); 
  12.     } 
<span style="background-color: rgb(255, 255, 255);">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);}</span>

最终从文件加载的时候仍然是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.     } 
<span style="background-color: rgb(255, 255, 255);">    public InputStream getInputStream() throws IOException {InputStream is;if (this.clazz != null) {is = this.clazz.getResourceAsStream(this.path);}</span>

如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; 

这篇关于Spring加载resource,classpath*:与classpath的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/973878

相关文章

Spring事务传播机制最佳实践

《Spring事务传播机制最佳实践》Spring的事务传播机制为我们提供了优雅的解决方案,本文将带您深入理解这一机制,掌握不同场景下的最佳实践,感兴趣的朋友一起看看吧... 目录1. 什么是事务传播行为2. Spring支持的七种事务传播行为2.1 REQUIRED(默认)2.2 SUPPORTS2

怎样通过分析GC日志来定位Java进程的内存问题

《怎样通过分析GC日志来定位Java进程的内存问题》:本文主要介绍怎样通过分析GC日志来定位Java进程的内存问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、GC 日志基础配置1. 启用详细 GC 日志2. 不同收集器的日志格式二、关键指标与分析维度1.

Java进程异常故障定位及排查过程

《Java进程异常故障定位及排查过程》:本文主要介绍Java进程异常故障定位及排查过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、故障发现与初步判断1. 监控系统告警2. 日志初步分析二、核心排查工具与步骤1. 进程状态检查2. CPU 飙升问题3. 内存

java中新生代和老生代的关系说明

《java中新生代和老生代的关系说明》:本文主要介绍java中新生代和老生代的关系说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、内存区域划分新生代老年代二、对象生命周期与晋升流程三、新生代与老年代的协作机制1. 跨代引用处理2. 动态年龄判定3. 空间分

Java设计模式---迭代器模式(Iterator)解读

《Java设计模式---迭代器模式(Iterator)解读》:本文主要介绍Java设计模式---迭代器模式(Iterator),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,... 目录1、迭代器(Iterator)1.1、结构1.2、常用方法1.3、本质1、解耦集合与遍历逻辑2、统一

Java内存分配与JVM参数详解(推荐)

《Java内存分配与JVM参数详解(推荐)》本文详解JVM内存结构与参数调整,涵盖堆分代、元空间、GC选择及优化策略,帮助开发者提升性能、避免内存泄漏,本文给大家介绍Java内存分配与JVM参数详解,... 目录引言JVM内存结构JVM参数概述堆内存分配年轻代与老年代调整堆内存大小调整年轻代与老年代比例元空

深度解析Java DTO(最新推荐)

《深度解析JavaDTO(最新推荐)》DTO(DataTransferObject)是一种用于在不同层(如Controller层、Service层)之间传输数据的对象设计模式,其核心目的是封装数据,... 目录一、什么是DTO?DTO的核心特点:二、为什么需要DTO?(对比Entity)三、实际应用场景解析

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

深度解析Java项目中包和包之间的联系

《深度解析Java项目中包和包之间的联系》文章浏览阅读850次,点赞13次,收藏8次。本文详细介绍了Java分层架构中的几个关键包:DTO、Controller、Service和Mapper。_jav... 目录前言一、各大包1.DTO1.1、DTO的核心用途1.2. DTO与实体类(Entity)的区别1