spring中资源的加载


spring中资源的加载

对于资源的加载这个场景首先要划分边界,spring抽象出两个组件:ResourceResourceLoader

Resource接口

Resource是对资源的一种抽象,提供一系列操作文件的方法

定义

  • resource.java
public interface Resource extends InputStreamSource {
    //文件是否存在
    boolean exists();
    //文件是否可读
    boolean isReadable();
    //文件是否打开
    boolean isOpen();
    //返回统一资源定位器(URL)
    URL getURL() throws IOException;
    //返回URI
    URI getURI() throws IOException;
    //返回文件
    File getFile() throws IOException;
    //文件最后修改时间
    long lastModified() throws IOException;
    //文件文件相对路径
    Resource createRelative(String var1) throws IOException;
    //返回文件名称
    String getFilename();
    //返回文件描述
    String getDescription();
}

子类

类名 作用
FileSystemResource 对 java.io.File 类型资源的封装
ByteArrayResource 对字节数组提供的数据的封装
UrlResource 对 java.net.URL类型资源的封装
ClassPathResource class path 类型资源的实现。使用给定的 ClassLoader 或者给定的 Class 来加载资源
InputStreamResource 将给定的 InputStream 作为一种资源的 Resource 的实现类

AbstractResource

AbstractResource是Resource的默认抽象类,实现了大部分公共方法;

ResourceLoader

ResourceLoader定义如何加载Resource的接口

定义

public interface ResourceLoader {

	/** Pseudo URL prefix for loading from the class path: "classpath:". */
	String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;

	Resource getResource(String location);

	@Nullable
	ClassLoader getClassLoader();

}
  • Resource getResource(String location)
    根据地址返回Resource,不保证文件是否存在,因此需要调用**exists()**进行判断

  • getClassLoader()
    getClassLoader() 方法,返回 ClassLoader 实例

DefaultResourceLoader.java

@Override
	public Resource getResource(String location) {
		Assert.notNull(location, "Location must not be null");

        //1. 首先通过ProtocolResolver来加载
		for (ProtocolResolver protocolResolver : this.protocolResolvers) {
			Resource resource = protocolResolver.resolve(location, this);
			if (resource != null) {
				return resource;
			}
		}

        //2. 用ClassPathResource加载
		if (location.startsWith("/")) {
			return getResourceByPath(location);
		}
		else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
			return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
		}
		else {
			try {
                //3. 尝试用FileUrlResource或UrlResource进行加载
				URL url = new URL(location);
				return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
			}
            //4. url类型加载不到,继续使用ClassPathResource方式进行加载
			catch (MalformedURLException ex) {
				// No URL -> resolve as resource path.
				return getResourceByPath(location);
			}
		}
	}

ProtocolResolver

ProtocolResolver用户自定义协议资源解决策略

代码演示

ResourceLoader loader = new DefaultResourceLoader();

Resource fileResource1 = loader.getResource("D:/text.txt");
Resource fileResource2 = loader.getResource("/text.txt");

Resource urlResource1 = loader.getResource("file:/Users/text.txt");
Resource urlResource2 = loader.getResource("http://www.baidu.com");

System.out.println("fileResource1.class = " + fileResource1.getClass().getSimpleName());
System.out.println("fileResource2.class = " + fileResource1.getClass().getSimpleName());

System.out.println("urlResource1.class = " + urlResource1.getClass().getSimpleName());
System.out.println("urlResource2.class = " + urlResource2.getClass().getSimpleName());
  • 运行结果

8dJXjg.png

由于fileResource1资源不存在,因此抛出异常,使用ClassPathResource来加载资源

FileSystemResourceLoader

FileSystemResourceLoader是对file文件的加载的优化

  • getResourceByPath(String path)
protected Resource getResourceByPath(String path) {
    if (path != null && path.startsWith("/")) {
        path = path.substring(1);
    }

    return new FileSystemResourceLoader.FileSystemContextResource(path);
}

getResourceByPath方法针对file的重写,自然返回的都是FileSystemContextResource类型的Resource

ClassRelativeResourceLoader

  • getResourceByPath(String path)
@Override
protected Resource getResourceByPath(String path) {
	return new ClassRelativeContextResource(path, this.clazz);
}

ClassRelativeResourceLoader是针对加载ClassPathResource子类ClassRelativeContextResource文件的重写

ResourcePatternResolver

ResourcePatternResolver是针对ResourceLoader的增强,定义返回多个Resource的方法

总结

  1. srping通过设计出抽象的资源(Resource)和资源加载器(ResourceLoader)让加载资源这个业务场景,变的更加的边界清晰和松耦合
  2. AbstrctResource是Resource的抽象实现类,实现了Resource大部分接口,使用模板方法
  3. DefaultResourceLoader是ResourceLoader默认实现,实现了最级别的方法资源的方法,并提供了一些公共接口为子类的扩展提供便利。
  4. PathMatchingResourcePatternResolver实现了ResourcePatternResolver(一个允许返回多个资源文件的ResourceLoder接口),是一个比较完整的ResourceLoader

  TOC