/**
* Return the path within the enclosing 'context'. * This is typically path relative to a context-specific root directory, * e.g. a ServletContext root or a PortletContext root. */ 3.3 ClassRelativeResourceLoaderorg.springframework.core.io.ClassRelativeResourceLoader 类也是 DefaultResourceLoader 的另一个实现子类,与 FileSystemResourceLoader 类似,也同样重写了 getResourceByPath() 方法,也内部维护了一个私有的内部类 ClassRelativeContextResource , 具体代码如下:
/** * 从给定的 class 下加载资源 * {@link ResourceLoader} implementation that interprets plain resource paths * as relative to a given {@code java.lang.Class}. * * @author Juergen Hoeller * @since 3.0 * @see Class#getResource(String) * @see ClassPathResource#ClassPathResource(String, Class) */ public class ClassRelativeResourceLoader extends DefaultResourceLoader { private final Class<?> clazz; /** * Create a new ClassRelativeResourceLoader for the given class. * @param clazz the class to load resources through */ public ClassRelativeResourceLoader(Class<?> clazz) { Assert.notNull(clazz, "Class must not be null"); this.clazz = clazz; setClassLoader(clazz.getClassLoader()); } /** * 重写getResourceByPath 方法 , 返回一个ClassRelativeContextResource 资源类型 * @param path the path to the resource * @return */ @Override protected Resource getResourceByPath(String path) { return new ClassRelativeContextResource(path, this.clazz); } /** * 继承 ClassPathResource 定义资源类型,实现ContextResource 中的 getPathWithinContext 方法, * * ClassPathResource that explicitly expresses a context-relative path * through implementing the ContextResource interface. */ private static class ClassRelativeContextResource extends ClassPathResource implements ContextResource { private final Class<?> clazz; /** * 调用父类 ClassPathResource 对资源进行初始化 * @param path * @param clazz */ public ClassRelativeContextResource(String path, Class<?> clazz) { super(path, clazz); this.clazz = clazz; } @Override public String getPathWithinContext() { return getPath(); } /** * 重写 ClassPathContext 中方法, 通过给定的路径返回一个ClassRelativeContextResource资源 * @param relativePath the relative path (relative to this resource) * @return */ @Override public Resource createRelative(String relativePath) { String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath); return new ClassRelativeContextResource(pathToUse, this.clazz); } } } 3.4 ResourcePatternResolverorg.springframework.core.io.support.ResourcePatternResolver 是对 ResourceLoader 的一个扩展,我们在 ResourceLoader 中通过 getResource 方法获取 Resource 实例时,只能通过一个 location 来获取一个 Resource , 而不能获取到多个 Resource , 当我们需要加载多个资源时,只能通过调用多次的该方法来实现,所以spring 提供了 ResourcePatternResolver 对其进行了扩展,实现了通过 location 来加载多个资源,类的定义如下:
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. * <p>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; }
可以看到 ResourcePatternResolver 新增加了一个方法 getResources ,返回一个 Resource 数组
这里我们要注意, ResourcePatternResolver 增加了一个新的协议前缀 classpath*: , 看到这里是不是大家可以很熟悉的想起我们在平时配置路径时经常会写 classpath: 和 classpath*: ,那么他们的区别就在这里,他们的资源加载方式时不一样的
3.5 PathMatchingResourcePatternResolverorg.springframework.core.io.support.PathMatchingResourcePatternResolver 是 ResourcePatternResolver 的一个主要实现类,也是使用较多的一个实现类,我们可以来看一下,它主要实现了 新增前缀的解析,同时还支持 Ant 风格的路径匹配模式(如 : "**/*.xml" )
3.5.1 构造函数PathMatchingResourcePatternResolver 提供了三个构造函数:
/** * 内置 资源定位加载器 */ private final ResourceLoader resourceLoader; /** * Ant路径匹配器 */ private PathMatcher pathMatcher = new AntPathMatcher(); /** * 无参构造函数,当不指定内部加载器类型时,默认是 DefaultResourceLoader * Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader. * <p>ClassLoader access will happen via the thread context class loader. * @see org.springframework.core.io.DefaultResourceLoader */ public PathMatchingResourcePatternResolver() { this.resourceLoader = new DefaultResourceLoader(); } /** * 指定特定的资源定位加载器 * Create a new PathMatchingResourcePatternResolver. * <p>ClassLoader access will happen via the thread context class loader. * @param resourceLoader the ResourceLoader to load root directories and * actual resources with */ public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) { Assert.notNull(resourceLoader, "ResourceLoader must not be null"); this.resourceLoader = resourceLoader; } /** * 使用默认的资源加载器,但是传入 classLoader ,使用特定的类加载 * Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader. * @param classLoader the ClassLoader to load classpath resources with, * or {@code null} for using the thread context class loader * at the time of actual resource access * @see org.springframework.core.io.DefaultResourceLoader */ public PathMatchingResourcePatternResolver(@Nullable ClassLoader classLoader) { this.resourceLoader = new DefaultResourceLoader(classLoader); }我们可以看到,当构造函数不提供 ResourceLoader 时,默认是 DefaultResourceLoader
3.5.2 getResource