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 方法-- |