博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring源码情操陶冶-PathMatchingResourcePatternResolver路径资源匹配溶解器
阅读量:4496 次
发布时间:2019-06-08

本文共 9831 字,大约阅读时间需要 32 分钟。

本文简单的分析下spring对某个目录下的class资源是如何做到全部的加载

PathMatchingResourcePatternResolver#getResources

PathMatchingResourcePatternResolverResourcePatternResolver的实现类,主要实现的方法为getResources(String locationPattern),具体代码如下,以classpath*:com/question/**/*.class为例

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。找寻classpath路径下的根目录全路径,包含jar、zip包                //比如classpath*:com/question/                return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));            }        }        else {            //一般此处针对classpath:开头的资源加载            int prefixEnd = locationPattern.indexOf(":") + 1;            if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {                // a file pattern 加载某个目录                return findPathMatchingResources(locationPattern);            }            else {                // a single resource with the given name优先加载classpath路径下的项目对应资源,找不到才查找jar、zip资源                return new Resource[] {getResourceLoader().getResource(locationPattern)};            }        }    }

PathMatchingResourcePatternResolver#findPathMatchingResources()

protected方法,查找指定路径下的所有资源,同时支持zip、jar中资源的查找

protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {        //首先定位根目录路径,例如classpath*:com/question/        String rootDirPath = determineRootDir(locationPattern);        //默认为**/*.class        String subPattern = locationPattern.substring(rootDirPath.length());        //递归函数的调用,此处会调用PathMatchingResourcePatternResolver#findAllClassPathResources方法加载根目录,找寻classpath路径下的根目录全路径,包含jar、zip包        Resource[] rootDirResources = getResources(rootDirPath);                Set
result = new LinkedHashSet
(16); for (Resource rootDirResource : rootDirResources) { //判断是否含有协议为bundle的资源,没有则返回原值 rootDirResource = resolveRootDirResource(rootDirResource); //vfs协议 if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) { result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher())); } //jar协议、zip协议、wsjar协议、vfszip协议 else if (isJarResource(rootDirResource)) { //从jar包中找寻相应的所有class文件 result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern)); } else { //加载非jar、zip包的项目资源 result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern)); } } if (logger.isDebugEnabled()) { logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result); } return result.toArray(new Resource[result.size()]); }

为了理解得更清楚,我们再抽取必要的代码进行分析,比如PathMatchingResourcePatternResolver#findAllClassPathResources()PathMatchingResourcePatternResolver#doFindPathMatchingFileResources()

  • PathMatchingResourcePatternResolver#findAllClassPathResources
    通过classloader来加载资源目录,代码如下
protected Resource[] findAllClassPathResources(String location) throws IOException {        String path = location;        //例如com/question/        if (path.startsWith("/")) {            path = path.substring(1);        }        //真实查找方法        Set
result = doFindAllClassPathResources(path); return result.toArray(new Resource[result.size()]); }

进而看PathMatchingResourcePatternResolver#doFindAllClassPathResources()

protected Set
doFindAllClassPathResources(String path) throws IOException { Set
result = new LinkedHashSet
(16); ClassLoader cl = getClassLoader(); //通过classloader来加载资源目录,这里也会去找寻classpath路径下的jar包或者zip包 Enumeration
resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path)); while (resourceUrls.hasMoreElements()) { URL url = resourceUrls.nextElement(); //对找到的路径保存为UrlResource对象放入set集合中 result.add(convertClassLoaderURL(url)); } if ("".equals(path)) { //加载jar协议的资源 addAllClassLoaderJarRoots(cl, result); } return result; }

Note:一般而言找到的结果为一个,也就是file协议的项目工程资源目录,不建议查找的base-package含有jar包的资源目录,比如org.springframework

  • PathMatchingResourcePatternResolver#doFindPathMatchingFileResources()
    查找指定目录下的所有文件,这里特指class文件
protected Set
doFindPathMatchingFileResources(Resource rootDirResource, String subPattern) throws IOException { File rootDir; try { //获取绝对路径对应的file rootDir = rootDirResource.getFile().getAbsoluteFile(); } catch (IOException ex) { if (logger.isWarnEnabled()) { logger.warn("Cannot search for matching files underneath " + rootDirResource + " because it does not correspond to a directory in the file system", ex); } //异常则返回空的集合 return Collections.emptySet(); } return doFindMatchingFileSystemResources(rootDir, subPattern); }

进而看真实的查找方法doFindMatchingFileSystemResources(),代码如下

protected Set
doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException { if (logger.isDebugEnabled()) { logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]"); } //真实的调用方法 Set
matchingFiles = retrieveMatchingFiles(rootDir, subPattern); Set
result = new LinkedHashSet
(matchingFiles.size()); for (File file : matchingFiles) { //对查找到的资源包装为FileSystemResource对象 result.add(new FileSystemResource(file)); } return result; }

继续观察真实加载文件资源的方法retriveMatchingFiles(),代码如下

protected Set
retrieveMatchingFiles(File rootDir, String pattern) throws IOException { //根目录不存在?返回空集合 if (!rootDir.exists()) { // Silently skip non-existing directories. if (logger.isDebugEnabled()) { logger.debug("Skipping [" + rootDir.getAbsolutePath() + "] because it does not exist"); } return Collections.emptySet(); } //不是目录?返回为空 if (!rootDir.isDirectory()) { // Complain louder if it exists but is no directory. if (logger.isWarnEnabled()) { logger.warn("Skipping [" + rootDir.getAbsolutePath() + "] because it does not denote a directory"); } return Collections.emptySet(); } //不可读?返回为空 if (!rootDir.canRead()) { if (logger.isWarnEnabled()) { logger.warn("Cannot search for matching files underneath directory [" + rootDir.getAbsolutePath() + "] because the application is not allowed to read the directory"); } return Collections.emptySet(); } //转换根目录全路径为标准的查找路径 String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/"); if (!pattern.startsWith("/")) { fullPattern += "/"; } //查找类型为.class文件 fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/"); Set
result = new LinkedHashSet
(8); doRetrieveMatchingFiles(fullPattern, rootDir, result); return result; }

接着瞧doRetriveMathingFiles的重载方法,代码如下

protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set
result) throws IOException { if (logger.isDebugEnabled()) { logger.debug("Searching directory [" + dir.getAbsolutePath() + "] for files matching pattern [" + fullPattern + "]"); } //从根目录开始罗列文件集合 File[] dirContents = dir.listFiles(); if (dirContents == null) { //查找到没有了则直接返回 if (logger.isWarnEnabled()) { logger.warn("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]"); } return; } //遍历 for (File content : dirContents) { //获取当前文件路径 String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/"); //查找到的子文件仍是目录且以根目录为开头 if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) { if (!content.canRead()) { if (logger.isDebugEnabled()) { logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() + "] because the application is not allowed to read the directory"); } } else { //递归调用查找所有的文件 doRetrieveMatchingFiles(fullPattern, content, result); } } //查看当前文件路径是否满足**/*.class格式,满足则添加 if (getPathMatcher().match(fullPattern, currPath)) { result.add(content); } } }

小结

  1. classpath*:表示查找classpath路径下的所有符合条件的资源,包含jar、zip等资源;classpath:表示优先在项目的资源目录下查找,找不到才去jar、zip等资源中查找

  2. 该类可以帮助spring查找到符合ant-style格式的所有资源,所以富有借鉴意义。附:ant-style指的是类似*/?此类的匹配字符

转载于:https://www.cnblogs.com/question-sky/p/6959493.html

你可能感兴趣的文章
Zend_Db_Table->insert ()和zend_db_adapter::insert方法返回值不同
查看>>
递归问题
查看>>
Hyperledger下子项目
查看>>
Linq-查询上一条下一条
查看>>
常见前端开发的题目,可能对你有用
查看>>
BeautifulSoap库入门
查看>>
乐观锁与悲观锁
查看>>
Codeforces Round #328 (Div. 2)D. Super M 虚树直径
查看>>
Java判断是否为移动端
查看>>
chromedriver下载链接以及对应版本
查看>>
[SimplePlayer] 6. 音频同步
查看>>
把一个SVN项目的目录结构 导入到另外一个空白的SVN项目里
查看>>
Android之Adapter用法总结-(转)
查看>>
总结列表显示ListView知识点
查看>>
android 教程实例系列
查看>>
lucene笔记
查看>>
tomcat无法正常shutdown
查看>>
zookeeper + dubbo 搭建
查看>>
根据前序遍历和中序遍历求出二叉树并打印
查看>>
UOJ356 [JOI2017春季合宿] Port Facility 【启发式合并】【堆】【并查集】
查看>>