在讲解如何支持之前,有必要先说明白对Spring而言,Resources是什么以及如何处理不当会发生什么问题;
好的,先说Resources是什么?大家都知道Spring容器在启动的时候会加载各种各样的配置文件,这些个用于不同目的的配置文件,就可以称之为Resources(至于中文翻译成什么,个人一直没有合适的选择),而且这些配置文件可能来源某个URL地址,项目的类路径,某个文件系统,ServletContext环境中,甚至来源于二进制文件以及某些其它的输入流,那么由于Resources的来源这么广泛,一旦处理来源不当,就会引发各种文件不存在或找不到异常,比如今天在论坛里面看到一个小伙伴的这个异常,部分异常信息如下:
[html] view plain copy
- org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [springmvc.xml]; nested exception is java.io.FileNotFoundException: class path resource [springmvc.xml] cannot be opened because it does not exist
JDK只提供了如java.net.URL、File等,缺少从类路径或者Web容器上下文中获取资源的操作类等,正因为如此,Spring框架提供了一个更为可靠的接口Resource用来抽象规范各种来源的资源,接口代码如下:
[html] view plain copy
- public interface Resource extends InputStreamSource {
- boolean exists();
- boolean isReadable();
- boolean isOpen();
- URL getURL() throws IOException;
- URI getURI() throws IOException;
- File getFile() throws IOException;
- long contentLength() throws IOException;
- long lastModified() throws IOException;
- Resource createRelative(String relativePath) throws IOException;
- String getFilename();
- String getDescription();
- }
[html] view plain copy
- public interface InputStreamSource {
- InputStream getInputStream() throws IOException;
- }
Spring框架提供了大量的对上述Resourse接口的实现类,来满足不同来源的Resource
1、UrlResource:这个类里面包装了java.net.URL,可以用来访问任何可以通过URL访问的对象,比如各类文件、HTTP目标以及FTP目标对象等;
2、ClassPathResource:该类代表了可以从类路径下面获取的Resource;
3、FileSystemResource:该类是java.io.File类处理的Resource实现,显然它可以支持File和URL;
4、ServletContextResource:该类是ServletContext资源的实现,它负责以相对于Web应用根目录的路径加载资源;
5、InputStreamResource:对应一个InputStream资源;
6、ByteArrayResource:二进制数组表示的资源,二进制数组资源可以在内存中通过程序构造;
和ByteArrayResource:这两者用的较少,只有在即特殊场合下才使用,就不做叙述;
既然有这么多种资源,访问不同类型的资源,必须使用相应的Resource实现类,这是比较麻烦的,对此Spring框架提供了一个ResourceLoader接口,该接口代码如下:
[html] view plain copy
- public interface ResourceLoader {
- /** Pseudo URL prefix for loading from the class path: "classpath:" */
- String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
- Resource getResource(String location);
- ClassLoader getClassLoader();
- }
它可以根据一个资源地址加载文件资源,那么这个资源地址是什么格式的呢?以下是从某本书上的截图
这个时候,我们会发现只要是前缀指定好,Spring会解析这个资源地址,自动去指定地方加载资源,这就要求我们在指定资源路径的时候一定确定好想要加载的资源到底是什么类型的资源,否则就会报各种找不到的异常,这样一来就解决了咱们在文章开头提到的问题。
需要说明的是,比如与"classpath:"对应的,还有一种"classpath*:"的前缀;假设有多个jar包或文件系统类路径都拥有一个相同的包名(如com.springframewok)前者只会加载第一个加载的com.springframework包下查找,而后者会扫描所有的这些jar包和文件系统类路径下面的内容;
上述ResourceLoader接口只支持带资源类型前缀的表达式,不支持Ant风格的资源路径表达式,ResourcePaternResolver扩展了ResourceLoader接口,
[html] view plain copy
- public interface ResourcePatternResolver extends ResourceLoader {
- /**
- * Pseudo URL prefix for all matching resources from the class path: "classpath*:"
- * This differs from ResourceLoader's classpath URL prefix in that it
- * retrieves all matching resources for a given name (e.g. "/beans.xml"),
- * for example in the root of all deployed JAR files.
- * @see org.springframework.core.io.ResourceLoader#CLASSPATH_URL_PREFIX
- */
- String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
- /**
- * Resolve the given location pattern into Resource objects.
- *
Overlapping resource entries that point to the same physical
- * resource should be avoided, as far as possible. The result should
- * have set semantics.
- * @param locationPattern the location pattern to resolve
- * @return the corresponding Resource objects
- * @throws IOException in case of I/O errors
- */
- Resource[] getResources(String locationPattern) throws IOException;
- }
该接口定义了一个新的接口方法:getResources(String locationPattern),该方法支持带资源类型前缀及Ant风格的资源路径表达式,由于Spring所有的ApplicationContext实现类都直接或间接地实现了该接口,所以我们可以在Spring配置文件中方式使用。Ant风格的资源地址,支持3种匹配符;
- ?:匹配文件名中的一个字符;
- * :匹配文件名中的任意个字符
- **:匹配多层路径
下面是几个示例:
- classpath:com/ssh/t?st.xml:匹配com/ssh路径下的com/ssh/test.xml、com/ssh/tast.xml等
- file:D:/conf/*Config.xml:匹配文件系统D:/conf路径下的所有文件以Config.xml为后缀的文件,比如匹配HibernateConf.xml,SpringConf.xml等;
- classpath:com/**/test/xml:匹配com类路径下(当前目录及其子孙目录)的test.xml文件,比如匹配:com/a/test.xml、com/a/b/c/d/test.xml等
只要是理解好了3种匹配符的作用,后续地使用没有问题,通过上面的说明,我们可以得出:只要是在Spring管理的环境配置中,可以放心大胆的按照上述规则制定各种资源文件