0
点赞
收藏
分享

微信扫一扫

Spring源码阅读总结-03-ResourceLoader资源加载器-03

ZSACH 2022-01-26 阅读 26

1.1 ResourcePatternResolver

ResourceLoaderResource getResource(String location),每次只能根据 location 返回一个 ResourceResourcePatternResolverResourceLoader 的扩展,它支持根据指定的资源路径匹配模式每次返回多个 Resource 实例

org.springframework.core.io.support;
// ResourceLoader 的扩展
public interface ResourcePatternResolver extends ResourceLoader {

	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

	// 根据指定的资源路径匹配模式每次返回多个 Resource 实例
	Resource[] getResources(String locationPattern) throws IOException;

}

1.2 PathMatchingResourcePatternResolver

ResourcePatternResolver 最常用的子类
支持 ResourceLoaderResourcePatternResolver 新增的 "classpath*:" 通配符前缀外,还支持 Ant风格的路径匹配模式(Ant风格类似于 "**/*.xml")


org.springframework.core.io.support;
// 继承 ResourcePatternResolver
public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
	// 资源定位器
	private final ResourceLoader resourceLoader;

	// Ant 路径匹配器 指 以 /开头的路径 如:/**/example
	private PathMatcher pathMatcher = new AntPathMatcher();

	// 默认构造
	public PathMatchingResourcePatternResolver() {
		this.resourceLoader = new DefaultResourceLoader();
	}

	// 指定 ResourceLoader 构造
	public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
		Assert.notNull(resourceLoader, "ResourceLoader must not be null");
		this.resourceLoader = resourceLoader;
	}
	
	// 指定 ClassLoader 构造
	public PathMatchingResourcePatternResolver(@Nullable ClassLoader classLoader) {
		this.resourceLoader = new DefaultResourceLoader(classLoader);
	}

	// 根据路径返回单个资源对象, 实现 ResourceLoader中的
	@Override
	public Resource getResource(String location) {
		return getResourceLoader().getResource(location);
	}

	// 根据指定的资源路径匹配模式每次返回多个Resource实例, 实现 ResourcePatternResolver 中的
	@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)) {
			// a class path resource (multiple resources for same name possible)
			// 路径包含通配符
			if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
				// a class path resource pattern
				// Find all resources that match the given location pattern
				// 匹配所有和 locationPattern 的 Resource 实例
				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.
			// 在 Tomcat 上只有在 “*/ ” 分隔符之后才为其 “war:”
			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)};
			}
		}
	}
}

1.3 findPathMatchingResources

当 locationPattern 中包含了通配符,则调用该方法进行资源加载

protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
		// 确定根路径、子路径
		String rootDirPath = determineRootDir(locationPattern);
		String subPattern = locationPattern.substring(rootDirPath.length());
		Resource[] rootDirResources = getResources(rootDirPath);
		Set<Resource> result = new LinkedHashSet<>(16);
		// 遍历,迭代
		for (Resource rootDirResource : rootDirResources) {
			rootDirResource = resolveRootDirResource(rootDirResource);
			URL rootDirUrl = rootDirResource.getURL();
			// bundle 资源类型
			if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {
				URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
				if (resolvedUrl != null) {
					rootDirUrl = resolvedUrl;
				}
				rootDirResource = new UrlResource(rootDirUrl);
			}
			// vfs 资源类型
			if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
				result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
			}
			// jar 资源类型
			else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
				result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
			}
			// 其它资源类型
			else {
				result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
			}
		}
		if (logger.isTraceEnabled()) {
			logger.trace("Resolved location pattern [" + locationPattern + "] to resources " + result);
		}
		return result.toArray(new Resource[0]);
	}

1.4 findAllClassPathResources

 locationPattern 以 "classpath*:" 开头但是不包含通配符,则调用此方法

	protected Resource[] findAllClassPathResources(String location) throws IOException {
		String path = location;
		if (path.startsWith("/")) {
			path = path.substring(1);
		}
		// 加载所有 classpath 资源
		Set<Resource> result = doFindAllClassPathResources(path);
		if (logger.isTraceEnabled()) {
			logger.trace("Resolved classpath location [" + location + "] to resources " + result);
		}
		return result.toArray(new Resource[0]);
	}

doFindAllClassPathResources方法 (真正执行加载的方法)
	protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
		Set<Resource> result = new LinkedHashSet<>(16);
		ClassLoader cl = getClassLoader();
		// 根据 ClassLoader 加载路径下的所有资源
		Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
		while (resourceUrls.hasMoreElements()) {
			URL url = resourceUrls.nextElement();
			// 将 URL 转换成 UrlResource
			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...
			// 加载路径下得所有 jar 包
			addAllClassLoaderJarRoots(cl, result);
		}
		return result;
	}

举报

相关推荐

0 条评论