前言
本篇博客主要简单说明 spring 加载资源路径的几种方式。以及 classpath
和 classpath*
的区别。
前提知识
首先 classpath是指 WEB-INF文件夹下的classes目录
解释classes含义:
- 存放各种资源配置文件,比如:log4j.properties,springmvc.xml
- 存放模板文件,比如:commons.tld
- 存放class文件对应的是项目开发时的src目录编译文件
总结:这是一个定位资源的入口
本篇主要介绍:
- spring 加载配置文件的几种方式
classpath
和classpath*
加载资源文件的区别
一、 使用构造方法加载spring配置文件
基本加载方式
使用构造器加载资源配置文件来获取 spring 容器,通常将字符串或字符串数组作为资源的位置路径。当这样的位置路径没有前缀(如没有加 classpath),如按照以下方式创建ClassPathXmlApplicationContext
:
ApplicationContext ctx = new ClassPathXmlApplicationContext("conf/appContext.xml");
由于使用了 ClassPathResource
加载,所以 spring 加载配置文件的时候,会从类路径开始加载,这种方式也是我们使用构造方法初始化 spring 容器时最常用的一种方式。
但如果使用 FileSystemXmlApplicationContext
来加载 spring 配置的话:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("conf/appContext.xml");
会从当前操作系统的文件系统根目录开始加载,比如 c:/conf/appContext.xml;
还有一种方式,如果使用 FileSystemXmlApplicationContext
来加载 spring 配置的话,加上classpath
前缀就会从类路径开始加载:
ApplicationContext ctx =
new FileSystemXmlApplicationContext("classpath:conf/appContext.xml");
这样就会从项目的类路径开始查找 conf/appContext.xml 配置文件了,但是值得注意的是:这种使用 Filesystem
加载的方式,本质上来说还是从系统的根目录开始查找的,但是使用了 classpath 前缀来告诉 spring 从项目的类路径开始查找。
ClassPathXmlApplicationContext
提供的其他方式
ClassPathXmlApplicationContext
这个类提供了一系列的构造方法来方便实例化,基本的想法是只要能够快速的定位到这个文件就可以加载,这个类的大纲结构如下图所示:
这里举个例子,假设文件的目录结构如下:
com/
foo/
services.xml
daos.xml
MessengerService.class
如果想要加载 services.xml
和 daos.xml
这两个配置文件的话,可以使用以下的方式:
ApplicationContext ctx = new ClassPathXmlApplicationContext(
new String[] {"services.xml", "daos.xml"}, MessengerService.class);
二、web.xml 中加载spring容器的配置文件
在使用 Java 开发 web项目时,需要在 web.xml 中指定 spring 配置文件的位置:
<!-- 全局配置参数 加载spring 配置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext-*.xml</param-value>
</context-param>
<!-- spring监听器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
因为通常配置文件有多个,所以一般会使用通配符的方式。可以使用 Ant-style 通配符来匹配,*
表示匹配 0 或任意数量的字符。加载可以分为两种方式:classpath
和 classpath*
。
Ant 路径通配符
Ant 路径通配符支持 ?
,*
,**
。这里需要注意的是,通配符匹配不会包括目录分隔符/
。
?
:匹配一个字符,如config?.xml
,将匹配config2.xml
*
:匹配 0 个或多个字符,如applicationContext-*.xml
可以匹配applicationContext-dao.xml
,applicationContext-service.xml
**
:匹配路径中的 0 个或多个目录 ,如cn/**/config.xml
将匹配cn/javax/spring/config.xml
,也匹配cn/config.xml
classpath
和 classpath*
的区别
- classpath 不包含通配符:用于加载类路径(包括 jar 包)中的一个且仅一个资源;对于多个匹配的也只返回一个。
- classpath 包含通配符: 用于加载类路径下的资源,但是不包括 jar 包;对于同名的重复的资源只返回一个。
- classpath* 不论是否包含通配符:都加载类路径(包括 jar 包)中的多个同名资源。
测试:
由于 spring-beans 包下有 META-INF 目录,目录下面有一些 license.txt 、notice.txt 资源,这里使用对比的方式分别测试如果在 项目resource 目录下包含有有同名文件和没有同名文件的情况。
测试代码如下:
package xyz.allenlei.test;
import java.io.IOException;
import org.junit.Test;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
/**
* 测试classpath 和 classpath* 的区别
* @author 雷聪
*
*/
public class SpringResourceTest {
/**
* classpath 加载资源的测试
* @throws IOException
*/
@Test
public void testClasspath() throws IOException {
// 创建路径匹配对象
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
// 加载资源文件
Resource[] resources = resolver.getResources("classpath:META-INF/notice.txt");
// 查看加载了几个资源文件
System.out.println(resources.length);
// 使用通配符方式加载
resources = resolver.getResources("classpath*:META-INF/*.txt");
// 查看加载了几个资源
System.out.println(resources.length);
}
}
有个小细节说明一下:
使用类路径加载资源文件 的时候第一个字符写不写/
是没有区别的,因为不管加不加解析的时候都是一样的,加上的话,解析的时候会自动去掉。下面是 spring 源码中解析路径中的一段:
protected Resource[] findAllClassPathResources(String location) throws IOException {
String path = location;
if (path.startsWith("/")) {
path = path.substring(1);
}
也就是说:
<param-value>classpath:spring/applicationContext-*.xml</param-value>
<param-value>classpath:/spring/applicationContext-*.xml</param-value>
对项目来说是没有区别的。
参考: https://spring.io/docs/reference
转载请注明: 雷聪的博客 » spring加载配置文件的方式