在JDK中 java.net.URL 适用于加载资源的类,但是 URL 的实现类都是访问网络资源的,并没有可以从类路径或者相对路径获取文件及 ServletContext , 虽然可以通过自定义扩展URL接口来实现新的处理程序,但是这是非常复杂的,同时 URL 接口中定义的行为也并不是很理想的 ,如检测资源的存在等的行为,这也是 spring 为什么自己全新的开发一套自己的资源加载策略, 同时它也满足下面的特点:
单一职责原则,将资源的定义和资源的加载的模型界限划的非常清晰
采用高度抽象,统一的资源定义和资源加载的策略和行为,资源加载返回给客户端的是抽象的资源,客户端根据资源的行为定义对其进行具体化的处理
2. Resource 接口spring 中的 Resource 接口目的在于成为一种功能更加强大的接口,用于抽象化对具体资源的访问,它继承了 org.springframework.core.io.InputStreamSource 接口,作为资源定义的顶级接口, Resource 内部定义了通用的方法,并且有它的子类 AbstractResource 来提供统一的默认实现,
Resouerce 接口定义:
//资源定义接口 public interface Resource extends InputStreamSource { /** * 检验资源是否是物理存在 */ boolean exists(); /** * 判断资源是否是可读的 */ default boolean isReadable() { return exists(); } /** * 判断资源是否是打开的,true为打开 */ default boolean isOpen() { return false; } /** * 判断该资源是否是文件 true为是 */ default boolean isFile() { return false; } /** * 返回该资源的URL句柄 */ URL getURL() throws IOException; /** * 返回该资源的URI句柄 */ URI getURI() throws IOException; /** * 获取该资源的File句柄 */ File getFile() throws IOException; /** * 返回一个ReadableByteChannel 作为NIO中的可读通道 */ default ReadableByteChannel readableChannel() throws IOException { return Channels.newChannel(getInputStream()); } /** * 获取资源内容的长度 */ long contentLength() throws IOException; /** * 返回该资源最后修改的时间戳 */ long lastModified() throws IOException; /** * 根据该资源的相对路径创建新资源 */ Resource createRelative(String relativePath) throws IOException; /** * 返回该资源的名称 */ @Nullable String getFilename(); /** * 返回该资源的描述 */ String getDescription(); }InputStreamSource 接口定义:
public interface InputStreamSource { /** * Return an {@link InputStream} for the content of an underlying resource. * <p>It is expected that each call creates a <i>fresh</i> stream. * <p>This requirement is particularly important when you consider an API such * as JavaMail, which needs to be able to read the stream multiple times when * creating mail attachments. For such a use case, it is <i>required</i> * that each {@code getInputStream()} call returns a fresh stream. * @return the input stream for the underlying resource (must not be {@code null}) * @throws java.io.FileNotFoundException if the underlying resource doesn't exist * @throws IOException if the content stream could not be opened */ InputStream getInputStream() throws IOException; }该 Resource 中一些最重要的方法:
getInputStream() :找到并打开资源,并返回一个资源以 InputStream 供读取,每次调用都会返回一个新的 InputStream ,调用者有责任关闭流
exists() :返回 boolean 指示此资源是否实际以物理形式存在。
isOpen() :返回, boolean 指示此资源是否表示具有打开流的句柄, 如果为 true , InputStream 则不能多次读取,必须只读取一次,然后将其关闭以避免资源泄漏。返回 false 所有常用资源实现(除外) InputStreamResource 可读
getDescription() :返回对此资源的描述,以便在使用该资源时用于错误输出。这通常是标准文件名或资源的实际 URL
** Resource 实现**
UrlResource : 包装一个 java.net.URL ,可用于访问通常可以通过 URL 访问的任何对象,例如文件, HTTP 目标, FTP 目标等。所有 URL 都有一个标准化的 String 表示形式,因此适当的标准化前缀可用于指示另一种 URL 类型。如: file : 访问文件系统路径, http : 通过 HTTP 协议 ftp : 访问资源,通过 FTP 访问资源等
ClassPathResource : 此类表示应从类路径获取的资源。它使用线程上下文类加载器( ClassLoader ),给定的类加载器或给定的类来加载资源
FileSystemResource : 是一个 Resource 执行 java.io.File 和 java.nio.file.Path 类型资源的封装,它支持 File 和 URL , 实现 WritableResource 接口,且从 Spring Framework 5.0 开始, FileSystemResource 使用 NIO2 API 进行读/写交互
ServletContextResource : 该 ServletContex t资源解释相关 Web 应用程序的根目录内的相对路径。
InputStreamResource : 将给定的 InputStream 作为一种资源的 Resource 的实现类
ByteArrayResource : 这是Resource给定字节数组的实现。它为给定的字节数组创建一个 ByteArrayInputStream
3. ResourceLoader 接口