ResourceLoader 架构概览
ResourceLoader接口用于返回Resource对象;其实现可以看作是一个生产Resource的工厂类。
可以分为两类:
第一类:默认资源加载器DefaultResourceLoader及其子类;
Spring提供了一个适用于所有环境的DefaultResourceLoader实现,可以返回ClassPathResource、UrlResource;还提供一个用于web环境的ServletContextResourceLoader,它继承了DefaultResourceLoader的所有功能,又额外提供了获取ServletContextResource的支持。
第二类: 应用上下文ApplicationContext接口及其实现类;
ApplicationContext的主要实现类ClassPathXmlApplicationContext和FileSystemXmlApplicationContext,前者默认从类路径加载配置文件,后者默认从文件系统中装载配置文件。本次不做说明,后面会单独介绍ApplicationContext。
ResourceLoader接口源码解析
//通过ResourceLoader获取资源
public interface ResourceLoader {
//加载的类路径伪URL前缀:“classpath:”
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
//根据提供的location参数返回相应的Resource对象
Resource getResource(String location);
//返回加载这些Resource的ClassLoader
ClassLoader getClassLoader();
}
ResourceLoader在进行加载资源时需要使用前缀来指定需要加载:“classpath:path”表示返回ClasspathResource,“http://path”和“file:path”表示返回UrlResource资源,如果不加前缀则需要根据当前上下文来决定,DefaultResourceLoader默认实现可以加载classpath资源
DefaultResourceLoader及其子类源码解析
public class DefaultResourceLoader implements ResourceLoader {
//加载该资源类加载器
private ClassLoader classLoader;
//构造函数
public DefaultResourceLoader() {
//默认:实际资源访问时使用的线程上下文类加载器
this.classLoader = ClassUtils.getDefaultClassLoader();
}
//构造函数
public DefaultResourceLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
//设置类加载器
public void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
//获取类加载器,未设置,则返回实际资源访问时使用的线程上下文类加载器
public ClassLoader getClassLoader() {
return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
}
//根据提供的location参数返回相应的资源句柄Resource。
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
//“classpath:”前缀,返回ClassPathResource对象
if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
// Try to parse the location as a URL...
//尝试将location转化为URL,再返回UrlResource对象
URL url = new URL(location);
return new UrlResource(url);
}
catch (MalformedURLException ex) {
//不是URL,则解析为资源路径。
return getResourceByPath(location);
}
}
}
//返回给定路径path上资源的资源句柄Resource。
protected Resource getResourceByPath(String path) {
//默认实现支持类路径位置
return new ClassPathContextResource(path, getClassLoader());
}
//类加载路径下的资源
private static class ClassPathContextResource extends ClassPathResource implements ContextResource {
public ClassPathContextResource(String path, ClassLoader classLoader) {
super(path, classLoader);
}
public String getPathWithinContext() {
return getPath();
}
// 关键 -> 创建相相对于当前资源路径下的资源。
// 假设当前的 file 路径为 D:/DEMO/HELLO.TXT,且 relativePath = GOOD.TXT
// 则该方法创建的资源路径为 D:/DEMO/GOOD.TXT
@Override
public Resource createRelative(String relativePath) {
String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
return new ClassPathContextResource(pathToUse, getClassLoader());
}
}
}
//servlet上下文资源加载器
public class ServletContextResourceLoader extends DefaultResourceLoader {
private final ServletContext servletContext;
//构造函数
public ServletContextResourceLoader(ServletContext servletContext) {
this.servletContext = servletContext;
}
//此实现支持Web应用程序根目录下的文件路径。
@Override
protected Resource getResourceByPath(String path) {
return new ServletContextResource(this.servletContext, path);
}
}
//文件系统资源加载器
public class FileSystemResourceLoader extends DefaultResourceLoader {
//将资源路径解析为文件系统路径。
@Override
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemContextResource(path);
}
//文件系统里面的资源
private static class FileSystemContextResource extends FileSystemResource implements ContextResource {
public FileSystemContextResource(String path) {
super(path);
}
public String getPathWithinContext() {
return getPath();
}
}
}
//类相关资源加载器
public class ClassRelativeResourceLoader extends DefaultResourceLoader {
private final Class clazz;
//创建一个指定类的相关资源加载器
public ClassRelativeResourceLoader(Class clazz) {
Assert.notNull(clazz, "Class must not be null");
this.clazz = clazz;
setClassLoader(clazz.getClassLoader());
}
protected Resource getResourceByPath(String path) {
return new ClassRelativeContextResource(path, this.clazz);
}
//获取类路径下的资源文件
private static class ClassRelativeContextResource extends ClassPathResource implements ContextResource {
private final Class clazz;
public ClassRelativeContextResource(String path, Class clazz) {
super(path, clazz);
this.clazz = clazz;
}
public String getPathWithinContext() {
return getPath();
}
@Override
public Resource createRelative(String relativePath) {
String pathToUse = StringUtils.applyRelativePath(getPath(), relativePath);
return new ClassRelativeContextResource(pathToUse, this.clazz);
}
}
}