8.3.2 ResourceLoader接口和 ResourceLoaderAware接口
Spring
提供如下两个标志性接口。
接口 | 描述 |
---|---|
Resourceloader |
该接口实现类的实例可以获得一个Resource 实例。 |
ResourceLoaderAware |
该接口实现类的实例将获得一个Resourceloader 的引用. |
# ResourceLoader接口 # | |
## ResourceLoader接口方法 ## | |
在ResourceLoader 接口里只有一个方法,如下所示: |
方法 | 描述 |
---|---|
Resource getResource(String location) |
该方法用于返回一个Resource 实例。 |
ApplicationContext
的实现类都实现ResourceLoader
接口,因此ApplicationContext
可用于直接获取Resource
实例。
某个ApplicationContext
实例获取Resource
实例时,默认采用与ApplicationContext
相同的资源访问策略。看如下代码:
1 | ApplicationContext ctx = new 实现类( |
从上面的代码中无法确定Spring
用哪个实现类来访问指定资源,
ApplicationContext使用相同策略访问资源是什么意思
Spring
将采用和ApplicationContext
相同的策略来访问资源。就是说:
- 如果这个
ApplicationContext
是FileSystemXmlApplicationContext
,则getResource()
方法获取到的resource
就是FileSystemResource
实例; - 如果这个
ApplicationContext
是ClassPathXmlApplicationContext
,则getResource()
方法获取到的resource
就是ClassPathResource
实例; - 如果这个
ApplicationContext
是XmlWebApplicationContext
,则getResource()
方法获取到的resource
就是ServletContextResource
实例。
从上面的介绍可以看出,当Spring
应用需要进行资源访间时,实际上并不需要直接使用Resource
实现类,而是调用ResourceLoader
实例的getResource()
方法来获得资源。 ResourceLoader
将会负责选择Resource
的实现类,也就是确定具体的资源访问策略,从而将应用程序和具体的资源访问策略分离开来,这就是典型的策略模式。
程序示例
1 | E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\ResourceLoader |
看如下示例程序,将使用ApplicationContext
来访问资源。
1 | package lee; |
上面程序中的第一行代码创建了一个ApplictionContext
对象,第二行代码通过该ApplictionContext
对象来获取资源。虽然上面程序并未明确指定采用哪一种Resource
实现类,而是仅仅通过ApplicactionContext
获得Resource
。不过由于使用的是ClassPathApplicationContext
来获取资源,所以Spring
将会使用ClassPathResource
实现类从类加载路径下访问资源。
程序执行结果如下:
1 | book.xml |
从运行结果可以看出, 通过ClassPathXmlApplicationContext
获取到的Resource
是ClassPathResource
实现类。
如果将ApplicationContext
改为使用FileSystemXmlApplicationContext
实现类,运行上面程序,将看到如下运行结果:
1 | book.xml |
从上面的执行结果可以看出,程序的Resource
实现类发生了改变,变为使用FileSystemResource
实现类。
为了保证得到上面的两次运行结果,需要分别在类加载路径(src/
目录)下、当前文件路径(项目路径
)下放置beans.xml
:和book.xml
两个文件(为了区分,本示例故意让两个路径下的book.xml
文件略有区别)
使用前缀强制指定使用哪个Resource实现类
另外,使用ApplicationContext
访问资源时,也可不理会ApplicationContext
的实现类,强制使用指定的ClassPathResource
、 FileSystemResource
等实现类,这可通过不同前缀
来指定,如下面的代码所示。
1 | //通过 classpath:前缀,强制使用ClasspathResource |
类似的,还可以使用标准的java.net.URL
前缀来强制使用UrlResource
,如下所示:
1 | //通过标准的file:前缀,强制使用UrlResource访问本地文件资源 |
常见前缀及其对应的访问策略
以下是常见的前缀及对应的访问策略。
前缀 | 描述 | ||
---|---|---|---|
classpath: |
以ClassPathResource 实例访问类加载路径下的资源。 |
||
file: |
以UrlResource 实例访问本地文件系统的资源 |
||
http: |
以UrlResource 实例访问基于HTTP 协议的网络资源。 |
||
无前缀 | 由ApplicationContext 的具体实现类来决定访问策略。 |
||
# ResourceLoaderAware # | |||
ResourceLoaderAware 完全类似于Spring 提供的BeanFactoryAware 、 BeanNameAware 接口。 |
|||
ResourceLoaderAware 接口提供了一个setResourceLoader() 方法,该方法将由Spring 容器负责调用,Spring 容器会传入一个ResourceLoader 对象作为setResourceLoader() 方法的参数。 |
|||
如果把实现ResourceLoaderAware 接口的Bean 类部署在Spring 容器中, Spring 容器会将自身当成ResourceLoader 作为参数传入setResourceLoader() 方法。由于ApplicationContext 的实现类都实现了ResourceLoader 接口, Spring 容器自身完全可作为ResourceLoader 使用。 |
|||
## 程序示例 ## | |||
|
例如,如下Bean
类实现了ResourceAware
接口。
1 | package org.crazyit.app.service; |
将该类部署在Spring
容器中, Spring
将会在创建完该Bean
的实例之后,自动调用该Bean
的setResourceLoader()
方法,调用该方法时会将容器自身作为参数传入。
如果需要验证这一点,程序可用TestBean
的getResourceLoader()
方法的返回值与Spring
容器进行"=="
运算符进行比较,将会发现使用"=="
比较返回true
,这表明两个引用指向相同的对象.
主类代码如下:
1 | package lee; |
运行结果:
1 | --执行setResourceLoader 方法-- |