Spring中classpath*:和classpath的区别

Spring中classpath*:和classpath的区别

以AbstractApplicationContext为例讲解

AbstractApplicationContext持有一个ResourcePatternResolver实例,该接口的定义如下

public interface ResourcePatternResolver extends ResourceLoader {

    /**
     * Pseudo URL prefix for all matching resources from the class path: "classpath*:"
     * This differs from ResourceLoader's classpath URL prefix in that it
     * retrieves all matching resources for a given name (e.g. "/beans.xml"),
     * for example in the root of all deployed JAR files.
     * @see org.springframework.core.io.ResourceLoader#CLASSPATH_URL_PREFIX
     */
    String CLASSPATH_ALL_URL_PREFIX = "classpath*:";

    /**
     * Resolve the given location pattern into Resource objects.
     * 

Overlapping resource entries that point to the same physical * resource should be avoided, as far as possible. The result should * have set semantics. * @param locationPattern the location pattern to resolve * @return the corresponding Resource objects * @throws IOException in case of I/O errors */ Resource[] getResources(String locationPattern) throws IOException; }

该接口扩展了ResourceLoader,提供了根据指定模式(例如Ant)的路径获取资源的方法。ResourceLoader则是提供了根据指定路径获取资源的能力。

AbstractApplicationContext持有的ResourcePatternResolver实例会在其无参构造函数中完成初始化

public AbstractApplicationContext() {
        this.resourcePatternResolver = getResourcePatternResolver();
    }
    
    protected ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }

getResourcePatternResolver可以被重写,例如AbstractRefreshableWebApplicationContext。我们暂时只分析AbstractApplicationContext。来看看PathMatchingResourcePatternResolver类,它实现了ResourcePatternResolver接口,来看看比较重要的方法

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 {
            // 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)};
            }
        }
    }

其中getPathMatcher默认为AntPathMatcher

跟着代码一行行走

  1. 如果传入的路径以classpath*:开头,分两种情况

    • 如果符合PathMatcher(此处可以简化为Ant风格),则执行findPathMatchingResources

      例如classpath*:*-db.properties

    • 如果不符合PathMatcher,则执行findAllClassPathResources

      例如classpath*:db.properties

  2. 如果传入的路径不以classpath:开头,分两种情况

    • 如果符合PathMatcher(此处可以简化为Ant风格),则执行findPathMatchingResources

      例如*-db.properties

    • 如果不符合PathMatcher,则调用其持有的ResourceLoader实例去获取指定资源。此时只获取到唯一一个资源,以AbstractApplicationContext为例,它将自己作为PathMatchingResourcePatternResolver的构造函数参数,因此PathMatchingResourcePatternResolver持有的ResourceLoader的实例就是AbstractApplicationContext自己,而AbstractApplicationContext继承自DefaultResourceLoader,因此,这个地方会调用DefaultResourceLoader的getResource方法

接下来看看上文提到的几个比较重要的方法做了什么

findPathMatchingResources

先看看其方法注释

Find all resources that match the given location pattern via the
Ant-style PathMatcher. Supports resources in jar files and zip files
 and in the file system.

该方法会递归查找所有所有符合规则的资源

findPathMatchingResources
Find all class location resources with the given location via the ClassLoader.
结论

其实从代码看来classpath*:*-db.properties和classpath:*-db.properties效果是一样的。而对于classpath*:db-properties和classpath:db-properties,前者会加载所有的db-properties,后者只会加载一个。可以这么简单归纳,但凡是Ant风格的location,都会去加载所有符合规则的资源,否则只有在指定了classpath*:情况下才会去加载所有指定location的资源,其他情况下只加载一个指定location的资源,即便是找到了多个

你可能感兴趣的:(Spring中classpath*:和classpath的区别)