spring如何解析通配符路徑

轉自: http://goodscript.iteye.com/blog/1161519

在spring的配置文件中、經常看見類似這樣的配置路徑: 

Java代碼  收藏代碼
  1. classpath:/com/module/**/*sql.xml  


系統會根據配置路徑自動加載符合路徑規則的xml文件 
假如讓你實現這樣的功能: 
根據一個通配符路徑加載符合規則的xml文件你會怎麼做? 

先看一個小例子: 

Java代碼  收藏代碼
  1. import java.io.IOException;  
  2.   
  3. import org.springframework.core.io.Resource;  
  4. import org.springframework.core.io.support.PathMatchingResourcePatternResolver;  
  5. import org.springframework.core.io.support.ResourcePatternResolver;  
  6.   
  7. public class XMLManager {  
  8.   
  9.     private String location = "classpath:*.xml";  
  10.   
  11.     public void readFile() throws IOException {  
  12.         ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();  
  13.         Resource[] source = resourceLoader.getResources(location);  
  14.         for (int i = 0; i < source.length; i++) {  
  15.             Resource resource = source[i];  
  16.             System.out.println(resource.getFilename());  
  17.   
  18.         }  
  19.     }  
  20.   
  21.     public static void main(String[] args) {  
  22.   
  23.         XMLManager m = new XMLManager();  
  24.         try {  
  25.             m.readFile();  
  26.         } catch (IOException e) {  
  27.             e.printStackTrace();  
  28.         }  
  29.     }  
  30. }  



輸出結果: 

Java代碼  收藏代碼
  1. applicationContext.xml  
  2. logback.xml  
  3. menu_my.xml  


是不是很簡單? 
只要調用PathMatchingResourcePatternResolver的getResources方法就可以實現我們想要的功能。 
下面深入研究一下spring的源碼PathMatchingResourcePatternResolver: 
1、getResources方法 

Java代碼  收藏代碼
  1. public Resource[] getResources(String locationPattern) throws IOException {  
  2.         Assert.notNull(locationPattern, "Location pattern must not be null");  
  3.         if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {  
  4.             // a class path resource (multiple resources for same name possible)  
  5.             if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {  
  6.                 // a class path resource pattern  
  7.                 return findPathMatchingResources(locationPattern);  
  8.             }  
  9.             else {  
  10.                 // all class path resources with the given name  
  11.                 return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));  
  12.             }  
  13.         }  
  14.         else {  
  15.             // Only look for a pattern after a prefix here  
  16.             // (to not get fooled by a pattern symbol in a strange prefix).  
  17.             int prefixEnd = locationPattern.indexOf(":") + 1;  
  18.             if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {  
  19.                 // a file pattern  
  20.                 return findPathMatchingResources(locationPattern);  
  21.             }  
  22.             else {  
  23.                 // a single resource with the given name  
  24.                 return new Resource[] {getResourceLoader().getResource(locationPattern)};  
  25.             }  
  26.         }  
  27.     }  


該方法主要是判斷locationPattern是否包含有通配符、如果包含通配符則調用findPathMatchingResources方法、沒有包含通配符就不需要解析了 
2、findPathMatchingResources方法 

Java代碼  收藏代碼
  1. protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {  
  2.     String rootDirPath = determineRootDir(locationPattern);  
  3.     String subPattern = locationPattern.substring(rootDirPath.length());  
  4.     Resource[] rootDirResources = getResources(rootDirPath);  
  5.     Set<Resource> result = new LinkedHashSet<Resource>(16);  
  6.     for (Resource rootDirResource : rootDirResources) {  
  7.         rootDirResource = resolveRootDirResource(rootDirResource);  
  8.         if (isJarResource(rootDirResource)) {  
  9.             result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));  
  10.         }  
  11.         else if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {  
  12.             result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));  
  13.         }  
  14.         else {  
  15.             result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));  
  16.         }  
  17.     }  
  18.     if (logger.isDebugEnabled()) {  
  19.         logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);  
  20.     }  
  21.     return result.toArray(new Resource[result.size()]);  
  22. }  


把locationPattern拆分成兩部分:rootDirPath 和subPattern 
rootDirPath是根目錄路徑 
subPattern是子目錄路徑匹配規則字符串 
歷遍根目錄下的所有子目錄、並得到所有的子目錄 
在doFindPathMatchingFileResources(rootDirResource, subPattern)方法中 
再根據子目錄逐個逐個去匹配subPattern 
3、doFindPathMatchingFileResources 

Java代碼  收藏代碼
  1. protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)  
  2.         throws IOException {  
  3.   
  4.     File rootDir;  
  5.     try {  
  6.         rootDir = rootDirResource.getFile().getAbsoluteFile();  
  7.     }  
  8.     catch (IOException ex) {  
  9.         if (logger.isWarnEnabled()) {  
  10.             logger.warn("Cannot search for matching files underneath " + rootDirResource +  
  11.                     " because it does not correspond to a directory in the file system", ex);  
  12.         }  
  13.         return Collections.emptySet();  
  14.     }  
  15.     return doFindMatchingFileSystemResources(rootDir, subPattern);  
  16. }  


跳轉到另一個方法doFindMatchingFileSystemResources: 

Java代碼  收藏代碼
  1. protected Set<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException {  
  2.     if (logger.isDebugEnabled()) {  
  3.         logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]");  
  4.     }  
  5.     Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);  
  6.     Set<Resource> result = new LinkedHashSet<Resource>(matchingFiles.size());  
  7.     for (File file : matchingFiles) {  
  8.         result.add(new FileSystemResource(file));  
  9.     }  
  10.     return result;  
  11. }  


retrieveMatchingFiles 

Java代碼  收藏代碼
  1. protected Set<File> retrieveMatchingFiles(File rootDir, String pattern) throws IOException {  
  2.     if (!rootDir.exists()) {  
  3.         // Silently skip non-existing directories.  
  4.         if (logger.isDebugEnabled()) {  
  5.             logger.debug("Skipping [" + rootDir.getAbsolutePath() + "] because it does not exist");  
  6.         }  
  7.         return Collections.emptySet();  
  8.     }  
  9.     if (!rootDir.isDirectory()) {  
  10.         // Complain louder if it exists but is no directory.  
  11.         if (logger.isWarnEnabled()) {  
  12.             logger.warn("Skipping [" + rootDir.getAbsolutePath() + "] because it does not denote a directory");  
  13.         }  
  14.         return Collections.emptySet();  
  15.     }  
  16.     if (!rootDir.canRead()) {  
  17.         if (logger.isWarnEnabled()) {  
  18.             logger.warn("Cannot search for matching files underneath directory [" + rootDir.getAbsolutePath() +  
  19.                     "] because the application is not allowed to read the directory");  
  20.         }  
  21.         return Collections.emptySet();  
  22.     }  
  23.     String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/");  
  24.     if (!pattern.startsWith("/")) {  
  25.         fullPattern += "/";  
  26.     }  
  27.     fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");  
  28.     Set<File> result = new LinkedHashSet<File>(8);  
  29.     doRetrieveMatchingFiles(fullPattern, rootDir, result);  
  30.     return result;  
  31. }  


調用遞歸方法: 
doRetrieveMatchingFiles 

Java代碼  收藏代碼
  1. protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) throws IOException {  
  2.     if (logger.isDebugEnabled()) {  
  3.         logger.debug("Searching directory [" + dir.getAbsolutePath() +  
  4.                 "] for files matching pattern [" + fullPattern + "]");  
  5.     }  
  6.     File[] dirContents = dir.listFiles();  
  7.     if (dirContents == null) {  
  8.         if (logger.isWarnEnabled()) {  
  9.             logger.warn("Could not retrieve contents of directory [" + dir.getAbsolutePath() + "]");  
  10.         }  
  11.         return;  
  12.     }  
  13.     for (File content : dirContents) {  
  14.         String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");  
  15.         if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {  
  16.             if (!content.canRead()) {  
  17.                 if (logger.isDebugEnabled()) {  
  18.                     logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() +  
  19.                             "] because the application is not allowed to read the directory");  
  20.                 }  
  21.             }  
  22.             else {  
  23.                 doRetrieveMatchingFiles(fullPattern, content, result);  
  24.             }  
  25.         }  
  26.         if (getPathMatcher().match(fullPattern, currPath)) {  
  27.             result.add(content);  
  28.         }  
  29.     }  
  30. }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章