美文网首页
ResourceLoader详解--PathMatchingRe

ResourceLoader详解--PathMatchingRe

作者: 北海北_6dc3 | 来源:发表于2019-03-17 23:29 被阅读0次

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*:/");

相关文章

网友评论

      本文标题:ResourceLoader详解--PathMatchingRe

      本文链接:https://www.haomeiwen.com/subject/mvcxpqtx.html