** * 加載資源的策略接口 (如類路徑和文件系統(tǒng)資源) */public interface ResourceLoader { /** 用于從類路徑加載的偽URL前綴:“classpath:”*/ String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; // 返回指定資源位置的資源句柄。 Resource getResource(String location); //暴露此ResourceLoader使用的ClassLoader。 @Nullable ClassLoader getClassLoader();}
我們可以看到此接口只有兩個(gè)核心操作,一個(gè)獲取資源,一個(gè)獲取classLoader.
先看看在ApplicationContext中使用的ResourcePatternResolver接口
public interface ResourcePatternResolver extends ResourceLoader { //匹配所有資源classpath*:,包括jar包中 String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; //將給定的位置模式解析為Resource對(duì)象。 Resource[] getResources(String locationPattern) throws IOException;}
一個(gè){@link ResourcePatternResolver}實(shí)現(xiàn),它能夠?qū)⒅付ǖ馁Y源位置路徑解析為一個(gè)或多個(gè)匹配的資源
匹配模式:
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 :
靜態(tài)構(gòu)造函數(shù)
@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是某個(gè)解析器的方法,后續(xù)我們會(huì)查看在哪種場(chǎng)景是用。
構(gòu)造函數(shù)有三種:默認(rèn)、resourceLoader,classLoader
//是用DefaultResourceLoader設(shè)置默認(rèn)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); }
關(guān)注的兩個(gè)變量
private final ResourceLoader resourceLoader; private PathMatcher pathMatcher = new AntPathMatcher();
核心重構(gòu)方法getResource:
@Override public Resource getResource(String location) { return getResourceLoader().getResource(location); }
我們可以看到getResource是通過調(diào)用resourceLoader的getResource方法來實(shí)現(xiàn)的。本身并沒有查找功能,只是一個(gè)中轉(zhuǎn)。
核心重構(gòu)方法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)}; } } }
判定標(biāo)準(zhǔn),是否開頭"classpath*:";及有無通配符,4個(gè)邏輯。
這個(gè)方法提供以"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; }
其中,第三行,我們可以看到,如果存在當(dāng)前l(fā)oader,則從當(dāng)前ClassLoader中獲取resources,如果不能存在,則從系統(tǒng)獲取【system-bootstrap】。
測(cè)試邏輯流程代碼:
ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver(); Resource[] result1 = resourceLoader.getResources("classpath*:/static/dist/admin.css"); Resource[] result2 = resourceLoader.getResources("classpath*:/");
聯(lián)系客服