ResourceLoader接口
**
* 加载资源的策略接口 (如类路径和文件系统资源)
*/
public interface ResourceLoader {
/** 用于从类路径加载的伪URL前缀:“classpath:”*/
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
// 返回指定资源位置的资源句柄。
Resource getResource(String location);
//暴露此ResourceLoader使用的ClassLoader。
@Nullable
ClassLoader getClassLoader();
}
我们可以看到此接口只有两个核心操作,一个获取资源,一个获取classLoader.
先看看在ApplicationContext中使用的ResourcePatternResolver接口
ResourcePatternResolver
public interface ResourcePatternResolver extends ResourceLoader {
//匹配所有资源classpath*:,包括jar包中
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
//将给定的位置模式解析为Resource对象。
Resource[] getResources(String locationPattern) throws IOException;
}
PathMatchingResourcePatternResolver
一个{@link ResourcePatternResolver}实现,它能够将指定的资源位置路径解析为一个或多个匹配的资源
匹配模式:
1.real URLs : file:C:/context.xml
2.pseudo-URLs :classpath:/context.xml
3.simple unprefixed paths :/WEB-INF/context.xml
4.Ant-style Patterns :
- /WEB-INF/*-context.xml
- com/mycompany/** /applicationContext.xml
- file:C:/some/path/*-context.xml
静态构造函数
@Nullable
private static Method equinoxResolveMethod;
static {
try {
// Detect Equinox OSGi (e.g. on WebSphere 6.1)
Class<?> fileLocatorClass = ClassUtils.forName("org.eclipse.core.runtime.FileLocator",
PathMatchingResourcePatternResolver.class.getClassLoader());
equinoxResolveMethod = fileLocatorClass.getMethod("resolve", URL.class);
logger.debug("Found Equinox FileLocator for OSGi bundle URL resolution");
}
catch (Throwable ex) {
equinoxResolveMethod = null;
}
}
equinoxResolveMethod是某个解析器的方法,后续我们会查看在哪种场景是用。
构造函数有三种:默认、resourceLoader,classLoader
//是用DefaultResourceLoader设置默认resourceLoader
public PathMatchingResourcePatternResolver() {
this.resourceLoader = new DefaultResourceLoader();
}
//传入制定资源的
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.resourceLoader = resourceLoader;
}
//传入classLoader,依然是用DefaultResourceLoader
public PathMatchingResourcePatternResolver(@Nullable ClassLoader classLoader) {
this.resourceLoader = new DefaultResourceLoader(classLoader);
}
关注的两个变量
private final ResourceLoader resourceLoader;
private PathMatcher pathMatcher = new AntPathMatcher();
核心重构方法getResource:
@Override
public Resource getResource(String location) {
return getResourceLoader().getResource(location);
}
我们可以看到getResource是通过调用resourceLoader的getResource方法来实现的。本身并没有查找功能,只是一个中转。
核心重构方法getResources:
@Override
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
// "classpath*:" 开始
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
//有通配符
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
// a class path resource pattern
return findPathMatchingResources(locationPattern);
}
else {
// all class path resources with the given name
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}
else {
// Generally only look for a pattern after a prefix here,
// and on Tomcat only after the "*/" separator for its "war:" protocol.
int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
locationPattern.indexOf(':') + 1);
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
// a file pattern
return findPathMatchingResources(locationPattern);
}
else {
// a single resource with the given name
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
}
判定标准,是否开头"classpath*:";及有无通配符,4个逻辑。
findAllClassPathResources方法
这个方法提供以"classpath*:"开头,并且无其他通配符的情况
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
Set<Resource> result = new LinkedHashSet<>(16);
ClassLoader cl = getClassLoader();
Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
while (resourceUrls.hasMoreElements()) {
URL url = resourceUrls.nextElement();
result.add(convertClassLoaderURL(url));
}
if ("".equals(path)) {
// The above result is likely to be incomplete, i.e. only containing file system references.
// We need to have pointers to each of the jar files on the classpath as well...
addAllClassLoaderJarRoots(cl, result);
}
return result;
}
其中,第三行,我们可以看到,如果存在当前loader,则从当前ClassLoader中获取resources,如果不能存在,则从系统获取【system-bootstrap】。
测试逻辑流程代码:
ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
Resource[] result1 = resourceLoader.getResources("classpath*:/static/dist/admin.css");
Resource[] result2 = resourceLoader.getResources("classpath*:/");
网友评论