上述代码中具体说明了执行的流程,其中 getResourceByPath(location) 的具体实现代码如下:
protected Resource getResourceByPath(String path) { return new ClassPathContextResource(path, getClassLoader()); } 3.1.3 ProtocolResolver全限定类名: org.springframework.core.io.ProtocolResolver ,是一个接口,用于用户自定义协议资源解析策略,是 DefaultResourceLoader 的 SPI ,允许处理自定义协议而无需将加载程序实现(或应用程序上下文实现)为子类,即不需要继承 ResourceLoader 的子类 DefaultResourceLoader , 而直接实现 ProtocolResolver 接口就可以自定义 ResourceLoader
@FunctionalInterface public interface ProtocolResolver { /** * 使用指定的ResourceLoader 来解析location路径的 资源 * Resolve the given location against the given resource loader * if this implementation's protocol matches. * @param location the user-specified resource location * @param resourceLoader the associated resource loader * @return a corresponding {@code Resource} handle if the given location * matches this resolver's protocol, or {@code null} otherwise */ @Nullable Resource resolve(String location, ResourceLoader resourceLoader); }在spring中该类并没有任何实现类,他需要用户自己实现,那么自定义的 ProtocolResolver 如何加载到spring中呢?在我们 DefaultResourceLoader 类中有一个方法 addProtocolResolver(ProtocolResolver resolver) 则是用来添加的
/** * Register the given resolver with this resource loader, allowing for * additional protocols to be handled. * <p>Any such resolver will be invoked ahead of this loader's standard * resolution rules. It may therefore also override any default rules. * @since 4.3 * @see #getProtocolResolvers() */ public void addProtocolResolver(ProtocolResolver resolver) { Assert.notNull(resolver, "ProtocolResolver must not be null"); this.protocolResolvers.add(resolver); } 3.2 FileSystemResourceLoader在 DefaultResourceLoader 中 getResourceByPath() 方法的处理是直接返回了一个 ClassPathContextResource 类型的资源,这其实是不完善的,在spring中 FileSystemResourceLoader 类继承了 DefaultResourceLoader ,同时重写了 getResourceByPath() 方法,使用标准的文件系统读入,并且返回 FileSystemContextResource 类型
public class FileSystemResourceLoader extends DefaultResourceLoader { /** * Resolve resource paths as file system paths. * <p>Note: Even if a given path starts with a slash, it will get * interpreted as relative to the current VM working directory. * @param path the path to the resource * @return the corresponding Resource handle * @see FileSystemResource * @see org.springframework.web.context.support.ServletContextResourceLoader#getResourceByPath */ @Override protected Resource getResourceByPath(String path) { if (path.startsWith("http://www.likecs.com/")) { path = path.substring(1); } return new FileSystemContextResource(path); } /** * FileSystemResource that explicitly expresses a context-relative path * through implementing the ContextResource interface. */ private static class FileSystemContextResource extends FileSystemResource implements ContextResource { public FileSystemContextResource(String path) { super(path); } @Override public String getPathWithinContext() { return getPath(); } } }
我们可以从 上面的代码中看到 在 FileSystemResourceLoader 中有一个私有的内部类 FileSystemContextResource , 这个类继承了 FileSystemResource ,同时实现了 ContextResource 接口
FileSystemContextResource 通过构造函数调用 FileSystemResource 的构造函数,创建 FileSystemResource 类型资源定义,同时实现 ContextResource 是为了实现其中的 getPathWithinContext() 方法,这个方法是用来获取上下文根路径的, 源码中这样写的 :