}
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}
protected Resource getResourceByPath(String path) {
return new ClassPathContextResource(path, getClassLoader());
}
FileSystemResourceLoader类
FileSystemResourceLoader继承自DefaultResourceLoader,它的getResource方法的实现逻辑和DefaultResourceLoader相同,不同的是它实现了自己的getResourceByPath方法,即当UrlResource创建失败时,它会使用FileSystemContextResource实例而不是ClassPathContextResource:
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemContextResource(path);
}
使用该类时要特别注意的一点:即使location以”/”开头,资源的查找还是相对于VM启动时的相对路径而不是绝对路径(从以上代码片段也可以看出,它会先截去开头的”/”),这个和Servlet Container保持一致。如果需要使用绝对路径,需要添加”file:”前缀。
ServletContextResourceLoader类
ServletContextResourceLoader类继承自DefaultResourceLoader,和FileSystemResourceLoader一样,它的getResource方法的实现逻辑和DefaultResourceLoader相同,不同的是它实现了自己的getResourceByPath方法,即当UrlResource创建失败时,它会使用ServletContextResource实例:
protected Resource getResourceByPath(String path) {
return new ServletContextResource(this.servletContext, path);
}
这里的path即使以”/”开头,也是相对ServletContext的路径,而不是绝对路径,要使用绝对路径,需要添加”file:”前缀。
PathMatchingResourcePatternResolver类
PathMatchingResourcePatternResolver类实现了ResourcePatternResolver接口,它包含了对ResourceLoader接口的引用,在对继承自ResourceLoader接口的方法的实现会代理给该引用,同时在getResources()方法实现中,当找到一个匹配的资源location时,可以使用该引用解析成Resource实例。默认使用DefaultResourceLoader类,用户可以使用构造函数传入自定义的ResourceLoader。
PathMatchingResourcePatternResolver还包含了一个对PathMatcher接口的引用,该接口基于路径字符串实现匹配处理,如判断一个路径字符串是否包含通配符(’*’、’ ’),判断给定的path是否匹配给定的pattern等。Spring提供了AntPathMatcher对PathMatcher的默认实现,表达该PathMatcher是采用Ant风格的实现。其中PathMatcher的接口定义如下:
public interface PathMatcher {
boolean isPattern(String path);
boolean match(String pattern, String path);
boolean matchStart(String pattern, String path);
String extractPathWithinPattern(String pattern, String path);
}
isPattern(String path):
判断path是否是一个pattern,即判断path是否包含通配符:
public boolean isPattern(String path) {
return (path.indexOf('*') != -1 || path.indexOf(' ') != -1);
}
match(String pattern, String path):
判断给定path是否可以匹配给定pattern:
matchStart(String pattern, String path):
判断给定path是否可以匹配给定pattern,该方法不同于match,它只是做部分匹配,即当发现给定path匹配给定path的可能性比较大时,即返回true。在PathMatchingResourcePatternResolver中,可以先使用它确定需要全面搜索的范围,然后在这个比较小的范围内再找出所有的资源文件全路径做匹配运算。
在AntPathMatcher中,都使用doMatch方法实现,match方法的fullMatch为true,而matchStart的fullMatch为false:
protected boolean doMatch(String pattern, String path, boolean fullMatch)
doMatch的基本算法如下:
1. 检查pattern和path是否都以”/”开头或者都不是以”/”开头,否则,返回false。
2. 将pattern和path都以”/”为分隔符,分割成两个字符串数组pattArray和pathArray。
3. 从头遍历两个字符串数组,如果遇到两给字符串不匹配(两个字符串的匹配算法再下面介绍),返回false,否则,直到遇到pattArray中的”**”字符串,或pattArray和pathArray中有一个遍历完。
4. 如果pattArray遍历完:
a) pathArray也遍历完,并且pattern和path都以”/”结尾或都不以”/”,返回true,否则返回false。
b) pattArray没有遍历完,但fullMatch为false,返回true。
c) pattArray只剩最后一个”*”,同时path以”/”结尾,返回true。
d) pattArray剩下的字符串都是”**”,返回tru