前言
Spring中整合了获取资源的工具,就是使用Resource接口。有关Resource接口的相关知识可以参考我的另一篇文档《Spring Resource接口进行资源访问》。
一. ResourceLoader接口
而Spring框架为了更方便的获取资源,尽量弱化程序员对各个Resource接口的实现类的感知,定义了另一个ResourceLoader接口。
- 接口有一个特别重要的方法:Resource getResource(String location),返回Resource实例
- 所有ApplicationContext实例都实现了这个方法
因此程序员在使用Spring容器时,可以不去过于计较底层Resource的实现,也不需要自己创建Resource实现类,而是直接使用applicationContext.getResource(),获取到bean容器本身的Resource,进而取到相关的资源信息。
public class ResourceTest implements ApplicationContextAware{
ApplicationContext applicationContext ;
public void getResourceTest() {
//通过applicationContext,只一步getResource(),就可以获取资源
Resource resource = applicationContext.getResource("spring-mvc.xml");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
二. Spring的Resource策略
applicationContext.getResource()会采用和ApplicationContext相同的策略来访问资源。
什么是相同的策略?就是与ApplicationContext创建方式相同的Resource:
- ClassPathXmlApplicationContext 则底层Resource是ClassPathResource实例
- FileSystemXmlApplicationContext 则底层Resource是FileSystemResource实例
- XmlWebApplicationContext 则底层Resource是ServletContextResource实例
但是,也可以用路径的前缀来强制指定Resource实现类。例如使用 classpath:指定使用ClassPathResource;使用file:指定使用UrlResource访问本地系统资源
//强制使用ClassPathResource
Resource resource = applicationContext.getResource("classpath:spring-mvc.xml");
//强制使用UrlResource
Resource resource = applicationContext.getResource("file:book.xml");
需要指出的是,这种指定前缀指定方法,仅对当次获取资源有效,后面的还会恢复默认的applicationContext的Resource实例。
//即使一开始创建用classpath:前缀,ApplicationContext的Resource还是FileSystemResource
applicationContext=new FileSystemXmlApplicationContext("classpath:bean.xml");
//这里还是用的FileSystemResource
applicationContext.getResource("book.xml");
三. ResourceLoaderAware接口
与BeanNameAware、ApplicationContextAware这些接口类似,Spring会自动调用实现了ResourceLoaderAware接口类方法:serResourceLoader(),将ApplicationContext的ResourceLoader注入进去,之后对它getResource(),就获取了系统的Resource了
public class ResourceBean implements ResourceLoaderAware {
private ResourceLoader resourceLoader;
public ResourceLoader getResourceLoader() {
return resourceLoader;
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
}
四. classpath*
与classpath区别是,classpath*会找到路径下所有符合规定的xml文件,进行加载;而classpath只找到第一个xml文件进行加载。
classpath*: 只能用在ApplicationContext中(通过Classloader.getResource()方法实现)。不可直接用在Resource前。所以如果不是Spring容器,而是直接使用Resource,想通过classpath*:前缀去一次性访问多个资源文件是行不通的。
五. 相对路径与绝对路径
可以参考文档:《Java文件路径》