spring 资源加载机制


Spring资源加载机制介绍

Java标准APIjava.net.URL能够处理URL资源,但是却不能处理”低等级”的资源,比如,没有标准化的URL实现用来加载类路径的资源, 虽然可以注册用于特殊URL前缀的新处理程序(类似于用于诸如http:的现有前缀的处理程序),但这通常相当复杂,并且URL接口仍然缺少某些理想的功能,例如用于检查是否存在的方法 指向的资源。

Resource接口定义

Spring的Resource接口抽象出了处理低级资源的方法:

public interface Resource extends InputStreamSource {

    boolean exists();

    boolean isOpen();

    URL getURL() throws IOException;

    File getFile() throws IOException;

    Resource createRelative(String relativePath) throws IOException;

    String getFilename();

    String getDescription();
}

Resource集成了InputStreamSource接口:

public interface InputStreamSource {

    InputStream getInputStream() throws IOException;
}

Resource中比较重要的方法是:

  • getInputStream(): 定位并打开资源,返回 InputStream 用于读取资源。作为调用方必须在使用完后关闭这个流。
  • exists(): 返回 boolean 值,判断资源是否存在.
  • isOpen(): 返回 boolean 值,判断当前资源是否已经在被处理,如果返回 true, InputStream 不能同时被调用,同一时间只能有一个调用者,并且必须被关闭防止资源。常规资源的实现通常返回 false
  • getDescription(): 通常用于处理异常时,返回该resource的说明。结果通常是返回文件的完整名称或是资源的实际URL

如果其底层实现支持的话,其他的方法则可以获取URLFile对象。

Spring本身许多需要操作资源的方法签名都是使用Resource接口,还有一部分Spring的API接收资源的路径,并且会根据路径的前缀自动创建合适的Resource对象。

尽管Spring经常使用Resource接口,但实际上,在自己的代码中单独使用Resource接口类作为通用实用工具类来访问资源非常有用,即使我们的代码不了解或不关心其他Spring的任何东西

ResourceAPI并没有替换任何功能,只是在相关的场景进行包装,比如,UrlResource包装了URL,并且实际上是使用这个URL来进行相关操作

Spring提供的Resource实现

UrlResource

UrlResource包装了java.net.URL,可以被用来获取常规资源,比如:文件、http资源、ftp资源,所有的URL都使用String进行表述,并且都包含了适当的资源路径前缀。file:用于读取文件系统,http:获取Http协议资源,ftp:获取FTP文件等

UrlResource可以通过构造器显式的创建,但是通常都是调用的Spring API接收String类型的路径参数自动创建合适的Resource实现类,当其无法识别路径前缀才创建UrlResource

ClassPathResource

ClassPathResource用于加载类路径的资源,使用当前线程的类加载器或给定的类加载器进行资源加载。如果类路径资源已经被解压到文件系统,则会将资源加载为java.io.File,为了解决这个问题,许多Resource的实现总是支持解析为java.net.URL

FileSystemResource

支持处理 java.io.Filejava.nio.file.Path

ServletContextResource

ServletContext资源的Resource实现,用于解析相关Web应用程序根目录中的相对路径。

它始终支持流访问和URL访问,但仅在Jar包被解压才允许java.io.File访问。 不管是解压还是直接访问文件系统、或者直接从JAR或其他类似数据库访问,取决于Servlet容器。

InputStreamResource

适用于给定的InputStream,应该被用于未指定的Resource的情况下进行适配。通常情况下isOpen()返回true,意味着不能多次读取流。

ByteArrayResource

将会创建一个ByteArrayResource基于给定的字节数组,比使用InputStreamResource更有效。

ResourceLoader接口

ResourceLoader接口需要被那些能够加载资源的对象实现:

public interface ResourceLoader {

    Resource getResource(String location);
}

所有的ApplicationContext都实现了ResourceLoader接口,因此可以被用来获取相关的Resource实例。

更具具体的ApplicationContext实现类,通常不需要加资源路径的前缀,比如通过ClassPathXmlApplicationContext加载:

public void loadresource(){
  Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
}

以上代码将返回ClassPathResource,如果换成FileSystemXmlApplicationContext,将会得到FileSystemResource,而对于WebApplicationContext来说,将会返回ServletContextResource

如果需要强制使用类路径加载则也可以指定路径前缀classpath:

public void loadresource(){
    Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
}

同样的,指定使用UrlResource需要指定filehttp 前缀:

public void loadresource(){
    Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
    Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
}

资源前缀表:

前缀案例解析
classpath:classpath:com/myapp/config.xml从类路径加载
file:file:///data/config.xml作为 URL 从文件系统加载
http:https://myserver/logo.png作为 URL加载
(none)/data/config.xml具体由ApplicationContext实现决定

ResourceLoaderAware接口

ResourceLoaderAware是一个特殊的回掉接口,任何实现这个接口的bean意味着bean需要获取ResourceLoader的引用。

public interface ResourceLoaderAware {

    void setResourceLoader(ResourceLoader resourceLoader);
}

Spring ioC容器会自动检测到所有实现ResourceLoaderAware接口的bean并且回掉setResourceLoader(ResourceLoader)方法,为当前bean设置ResourceLoader引用。另一种获取ResourceLoader的方式是通过@Autowired自动装配。


文章作者: Ubi-potato
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Ubi-potato !
评论
  目录