轉自: http://goodscript.iteye.com/blog/1161519
在spring的配置文件中、經常看見類似這樣的配置路徑:
- classpath:/com/module/**/*sql.xml
系統會根據配置路徑自動加載符合路徑規則的xml文件
假如讓你實現這樣的功能:
根據一個通配符路徑加載符合規則的xml文件你會怎麼做?
先看一個小例子:
- import java.io.IOException;
- import org.springframework.core.io.Resource;
- import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
- import org.springframework.core.io.support.ResourcePatternResolver;
- public class XMLManager {
- private String location = "classpath:*.xml";
- public void readFile() throws IOException {
- ResourcePatternResolver resourceLoader = new PathMatchingResourcePatternResolver();
- Resource[] source = resourceLoader.getResources(location);
- for (int i = 0; i < source.length; i++) {
- Resource resource = source[i];
- System.out.println(resource.getFilename());
- }
- }
- public static void main(String[] args) {
- XMLManager m = new XMLManager();
- try {
- m.readFile();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
輸出結果:
- applicationContext.xml
- logback.xml
- menu_my.xml
是不是很簡單?
只要調用PathMatchingResourcePatternResolver的getResources方法就可以實現我們想要的功能。
下面深入研究一下spring的源碼PathMatchingResourcePatternResolver:
1、getResources方法
- public Resource[] getResources(String locationPattern) throws IOException {
- Assert.notNull(locationPattern, "Location pattern must not be null");
- if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
- // a class path resource (multiple resources for same name possible)
- 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 {
- // Only look for a pattern after a prefix here
- // (to not get fooled by a pattern symbol in a strange prefix).
- 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
- return new Resource[] {getResourceLoader().getResource(locationPattern)};
- }
- }
- }
該方法主要是判斷locationPattern是否包含有通配符、如果包含通配符則調用findPathMatchingResources方法、沒有包含通配符就不需要解析了
2、findPathMatchingResources方法
- 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<Resource>(16);
- for (Resource rootDirResource : rootDirResources) {
- rootDirResource = resolveRootDirResource(rootDirResource);
- if (isJarResource(rootDirResource)) {
- result.addAll(doFindPathMatchingJarResources(rootDirResource, subPattern));
- }
- else if (rootDirResource.getURL().getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
- result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirResource, subPattern, getPathMatcher()));
- }
- else {
- result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
- }
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Resolved location pattern [" + locationPattern + "] to resources " + result);
- }
- return result.toArray(new Resource[result.size()]);
- }
把locationPattern拆分成兩部分:rootDirPath 和subPattern
rootDirPath是根目錄路徑
subPattern是子目錄路徑匹配規則字符串
歷遍根目錄下的所有子目錄、並得到所有的子目錄
在doFindPathMatchingFileResources(rootDirResource, subPattern)方法中
再根據子目錄逐個逐個去匹配subPattern
3、doFindPathMatchingFileResources
- protected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)
- throws IOException {
- File rootDir;
- try {
- 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<Resource> doFindMatchingFileSystemResources(File rootDir, String subPattern) throws IOException {
- if (logger.isDebugEnabled()) {
- logger.debug("Looking for matching resources in directory tree [" + rootDir.getPath() + "]");
- }
- Set<File> matchingFiles = retrieveMatchingFiles(rootDir, subPattern);
- Set<Resource> result = new LinkedHashSet<Resource>(matchingFiles.size());
- for (File file : matchingFiles) {
- result.add(new FileSystemResource(file));
- }
- return result;
- }
retrieveMatchingFiles
- protected Set<File> 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 += "/";
- }
- fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");
- Set<File> result = new LinkedHashSet<File>(8);
- doRetrieveMatchingFiles(fullPattern, rootDir, result);
- return result;
- }
調用遞歸方法:
doRetrieveMatchingFiles
- protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> 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);
- }
- }
- if (getPathMatcher().match(fullPattern, currPath)) {
- result.add(content);
- }
- }
- }