1.1 ResourcePatternResolver
 
ResourceLoader 的 Resource getResource(String location),每次只能根据 location 返回一个 Resource 。
ResourcePatternResolver 是 ResourceLoader 的扩展,它支持根据指定的资源路径匹配模式每次返回多个 Resource 实例
org.springframework.core.io.support;
public interface ResourcePatternResolver extends ResourceLoader {
	String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
	
	Resource[] getResources(String locationPattern) throws IOException;
}
 
1.2 PathMatchingResourcePatternResolver
 
ResourcePatternResolver 最常用的子类
支持 ResourceLoader 和 ResourcePatternResolver 新增的 "classpath*:" 通配符前缀外,还支持 Ant风格的路径匹配模式(Ant风格类似于 "**/*.xml")
org.springframework.core.io.support;
public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
	
	private final ResourceLoader resourceLoader;
	
	private PathMatcher pathMatcher = new AntPathMatcher();
	
	public PathMatchingResourcePatternResolver() {
		this.resourceLoader = new DefaultResourceLoader();
	}
	
	public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
		Assert.notNull(resourceLoader, "ResourceLoader must not be null");
		this.resourceLoader = resourceLoader;
	}
	
	
	public PathMatchingResourcePatternResolver(@Nullable ClassLoader classLoader) {
		this.resourceLoader = new DefaultResourceLoader(classLoader);
	}
	
	@Override
	public Resource getResource(String location) {
		return getResourceLoader().getResource(location);
	}
	
	@Override
	public Resource[] getResources(String locationPattern) throws IOException {
		Assert.notNull(locationPattern, "Location pattern must not be null");
		
		if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
			
			
			if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
				
				
				
				return findPathMatchingResources(locationPattern);
			}
			else {
				
				
				return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
			}
		}
		else {
			
			
			
			int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
					locationPattern.indexOf(':') + 1);
			
			if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
				
				return findPathMatchingResources(locationPattern);
			}
			else {
				
				
				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();
			
			if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {
				URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
				if (resolvedUrl != null) {
					rootDirUrl = resolvedUrl;
				}
				rootDirResource = new UrlResource(rootDirUrl);
			}
			
			if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
				result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
			}
			
			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);
		}
		
		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();
		
		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)) {
			
			
			
			addAllClassLoaderJarRoots(cl, result);
		}
		return result;
	}