spring核心技术之Resource资源理解

文章目录

      • 1 介绍
      • 2 Resource 接口
        • resource接口提供哪些功能?
      • 3 spring为我们提供了哪些内置的Resource实现
        • 3.1 URLResource
        • 3.2 ClassPathResource
        • 3.3 FileSystemResource
        • 3.4 InputStreamResource
        • 3.5 ByteArrayResource
      • 4 ResourceLoader 资源加载
      • 5 ResourceLoaderAware
      • 6 Resources as Dependencies
      • 7 Application Contexts and Resource Paths
        • 7.1 Constructing Application Contexts
        • 7.2Wildcards in Application Context Constructor Resource Paths
          • **Ant-style Patterns**
          • 可移植性
          • The `classpath*:` Prefix
        • FileSystemResource Caveats

spring如何处理资源(Resource),我们如何在spring中和资源(Resource)工作呢?

1 介绍

java.net.URL

可以处理各种复杂的URL(统一资源定位),缺点是对于所有访问底层资源的能力还不够

例如还没有一种URL的实现可以访问需要从类路径或相对于ServletContext获得的资源虽然可以为专门的URL前缀注册新的处理程序(类似于现有的用于前缀的处理程序,如http:),但这通常非常复杂。而且URL接口仍然缺少一些需要的功能,比如检查被指向的资源是否存在的方法

思考:Resource接口是用来解决什么问题的?即URL接口的这些不足。

2 Resource 接口

比URL接口更强,用于抽象对底层资源的访问。

对比URL接口,Resource接口有何不同,URL表示一个统一的资源定位符,一个指向万维网上“资源”的指针,相较于Resource更加侧重于web资源,且无法判断资源是否存在

相较于URL Resource接口实现资源的抽象,可以检查资源是否存在。

URL protocol,host,port,authority,file,ref

resource接口提供哪些功能?

判断 提供资源 其他
isReadable URL createRelative
isOpen URI contentLength
isFile File lastModified
exists InputStream ReadableByteChannel

通过字符串路径上的特殊前缀,指定必须创建和使用特定的资源实现,例如:ftp,http,file

资源抽象不能代替功能。在可能的地方进行包装。例如,UrlResource包装一个URL并使用包装后的URL来完成它的工作。

Resource接口的子类有以下这些

spring核心技术之Resource资源理解_第1张图片

3 spring为我们提供了哪些内置的Resource实现

  • UrlResource
  • ClassPathResource
  • FileSystemResource
  • ServletContextResource
  • InputStreamResource
  • ByteArrayResource

3.1 URLResource

包装了URL接口,可以用来访问File,Http,ftp等其他对象,UrlResource是由Java代码显式地使用UrlResource构造函数创建的,但通常在调用API方法时隐式地创建,该方法接受一个表示路径的字符串参数。对于后一种情况,JavaBeans PropertyEditor最终决定创建哪种类型的资源。路径字符串包含众所周知的(也就是)前缀(例如classpath:),它为该前缀创建一个适当的专门化资源。但是,如果它不识别前缀,则假定该字符串是标准URL字符串,并创建一个UrlResource。

PropertyEditor

3.2 ClassPathResource

从类路径下获取(classpath),隐式创建当字符串路径上的特殊前缀classpath:,PropertyEditor将创建一个ClassPathResource实例

3.3 FileSystemResource

File和Path 的Resource实现,支持解析File和URL

3.4 InputStreamResource

InputStream的Resource实现,只有在没有特定的资源实现可用时,才应该使用它。特别是,尽可能选择ByteArrayResource或任何基于文件的资源实现。如果您需要将资源描述符保存在某个地方,或者需要多次读取流,请不要使用它

3.5 ByteArrayResource

这是一个给定字节数组的资源实现。它为给定的字节数组创建一个ByteArrayInputStream。它对于从任何给定的字节数组加载内容都很有用,而不必求助于一次性使用的InputStreamResource

classpath: ClassPathResource
File,Path FileSystemResource
InputStreamResource 尽量不用
ByteArrayResource byte array --ByteArrayInputStream

4 ResourceLoader 资源加载

由可以返回(即加载)资源实例的对象来实现的。

public interface ResourceLoader {

    Resource getResource(String location);
}

applicationcontext于resouce的关系,如果没有指定特殊前缀,将获得适合于特定应用程序上下文的资源类型

上下文类型 返回资源类型
ClassPathXmlApplicationContext ClassPathResource
FileSystemXmlApplicationContext FileSystemResource
WebApplicationContext ServletContextResource

用例

Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");

资源和字符串路径的关系

Prefix Example Explanation
classpath: classpath:com/myapp/config.xml Loaded from the classpath.
file: file:///data/config.xml Loaded as a URL from the filesystem. See also FileSystemResource Caveats.
http: https://myserver/logo.png Loaded as a URL.
(none) /data/config.xml Depends on the underlying ApplicationContext.

5 ResourceLoaderAware

当类实现ResourceLoaderAware并部署到应用程序上下文中(作为Spring托管的bean)时,该类被应用程序上下文识别为ResourceLoaderAware。 然后,应用程序上下文调用setResourceLoader(ResourceLoader),将自身作为参数提供(请记住,Spring中的所有应用程序上下文均实现ResourceLoader接口)

在应用程序组件中,您还可以依赖自动装配ResourceLoader来实现ResourceLoaderAware接口。 “传统”构造函数和byType自动装配模式(如“自动装配协作器”中所述)能够分别为构造函数参数或setter方法参数提供ResourceLoader。 为了获得更大的灵活性(包括自动装配字段和多个参数方法的能力),请考虑使用基于注释的自动装配功能。 在这种情况下,只要有问题的字段,构造函数或方法带有@Autowired批注,ResourceLoader就会自动连接到需要ResourceLoader类型的字段,构造函数参数或方法参数中。 有关更多信息,请参见使用@Autowired。

ResourceLoaderAware 接口可以获得实现了ResourceLoader的类,好像还与自动装配存在着某种联系。自动装配的核心是BeanpostProcessor,其可以在bean实例化前后对bean进行一系列操作。

6 Resources as Dependencies

资源可以作为依赖

<bean id="myBean" class="...">
    <property name="template" value="some/resource/path/myTemplate.txt"/>
    <property name="template" value="file:///some/resource/path/myTemplate.txt"/>
    <property name="template" value="classpath:some/resource/path/myTemplate.txt">
bean>

7 Application Contexts and Resource Paths

应用上下文和资源路径

7.1 Constructing Application Contexts

创建应用上下文需要依赖资源路径,应用上下文从资源路径中加载bean的定义,当这样的位置路径没有前缀时,从该路径构建并用于加载bean定义的特定资源类型依赖于特定的应用程序上下文,并且适合于特定的应用程序上下文。

应用上下文类型 资源路径
new ClassPathXmlApplicationContext(“conf/appContext.xml”); classpath
new FileSystemXmlApplicationContext(“conf/appContext.xml”); file system
new FileSystemXmlApplicationContext(“classpath:conf/appContext.xml”); classpath

使用FileSystemXmlApplicationContext从类路径加载bean定义。但是,它仍然是FileSystemXmlApplicationContext。如果它随后被用作ResourceLoader,那么任何不带前缀的路径仍然被视为文件系统路径。

com/
  foo/
    services.xml
    daos.xml
    MessengerService.class

以下示例显示如何实例化由在名为service.xml和daos.xml(位于类路径中)的文件中定义的bean组成的ClassPathXmlApplicationContext实例。

ApplicationContext ctx = new ClassPathXmlApplicationContext(
    new String[] {"services.xml", "daos.xml"}, MessengerService.class);

感觉对于classpath 和包名之间的关系还是有点不清晰

7.2Wildcards in Application Context Constructor Resource Paths

应用程序上下文构造器资源路径中的通配符

此机制的一个用途是,当您需要进行组件样式的应用程序组装时。所有组件都可以将上下文定义片段“发布”到一个已知的位置路径,并且,当使用以classpath*:作为前缀的相同路径创建最终的应用程序上下文时,所有组件片段都会自动被获取。注意,这种通配符是特定于在应用程序上下文构造函数中使用资源路径的,在构建应用时进行解析。

与资源类型本身无关。您不能使用classpath*:前缀来构造实际的资源,因为一个资源一次只能指向一个资源。

多模块应用中的使用classpath*

Ant-style Patterns
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml

When the path location contains an Ant-style pattern, the resolver follows a more complex procedure to try to resolve the wildcard. It produces a Resource for the path up to the last non-wildcard segment and obtains a URL from it. If this URL is not a jar: URL or container-specific variant (such as zip: in WebLogic, wsjar in WebSphere, and so on), a java.io.File is obtained from it and used to resolve the wildcard by traversing the filesystem. In the case of a jar URL, the resolver either gets a java.net.JarURLConnection from it or manually parses the jar URL and then traverses the contents of the jar file to resolve the wildcards.

如果有路径机制含有 Ant-style pattern,解析器会使用更加复杂的程序尝试解析通配符。

匹配规则

The mapping matches URLs using the following rules:

  • ? matches one character
  • ***** matches zero or more characters
  • ** matches zero or more ‘directories’ in a path
  • {spring:[a-z]+} matches the regexp [a-z]+ as a path variable named “spring”

Some examples:

  • com/t?st.jsp - matches com/test.jsp but also com/tast.jsp or com/txst.jsp
  • com/*.jsp - matches all .jsp files in the com directory
  • com/**/test.jsp - matches all test.jsp files underneath the com path
  • org/springframework/**/*.jsp - matches all .jsp files underneath the org/springframework path
  • org/**/servlet/bla.jsp - matches org/springframework/servlet/bla.jsp but also org/springframework/testing/servlet/bla.jsp and org/servlet/bla.jsp
  • com/{filename:\w+}.jsp will match com/test.jsp and assign the value test to the filename variable
可移植性

如果指定的路径已经是一个文件URL(由于基本ResourceLoader是一个文件系统,所以它是隐式的,或者是显式的),则保证通配符可以完全可移植的方式工作。

如果指定的路径是类路径位置,则解析器必须通过调用Classloader.getResource()获得最后的非通配符路径段URL。 由于这只是路径的一个节点(而不是末尾的文件),因此实际上(在ClassLoader javadoc中)未定义确切返回的是哪种URL。 实际上,它始终是一个java.io.File,代表目录(类路径资源解析为文件系统位置)或某个jar URL(类路径资源解析为jar位置)。 尽管如此,此操作仍存在可移植性问题。

如果为最后一个非通配符段获取了jar URL,则解析程序必须能够从中获取java.net.JarURLConnection或手动解析jar URL,以便能够遍历jar的内容并解析通配符 。 这在大多数环境中确实有效,但在其他环境中则无效,因此我们强烈建议您在依赖特定环境之前,对来自jars的资源的通配符解析进行彻底测试

移植性于路径关系

路径样式 移植性是否有影响
file URL 无影响
classpath location 可能有一些
jar URL 彻底测试
The classpath*: Prefix

在构造基于xml的应用程序上下文时,位置字符串可以使用特殊的classpath*:前缀,如下面的示例所示

ApplicationContext ctx =
    new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");

这个特殊的前缀指定必须获取所有与给定名称匹配的类路径资源(在内部,这实际上是通过调用ClassLoader来实现的。然后合并形成最终的应用程序上下文定义

通配符类路径依赖于基础类加载器的getResources()方法。 由于当今大多数应用程序服务器都提供自己的类加载器实现,因此行为可能有所不同,尤其是在处理jar文件时。 检查classpath *是否可行的简单测试是使用classloader从classpath的jar中加载文件:getClass()。getClassLoader()。getResources(“ ”)。 尝试对具有相同名称但位于两个不同位置的文件进行此测试。 如果返回了不合适的结果,请检查应用程序服务器文档中可能影响类加载器行为的设置。

还可以在其余位置路径中将classpath *:前缀与PathMatcher模式结合使用(例如,classpath *:META-INF / *-beans.xml)。 在这种情况下,解析策略非常简单:在最后一个非通配符路径段上使用ClassLoader.getResources()调用,以获取类加载器层次结构中的所有匹配资源,然后从每个资源获取相同的PathMatcher解析 前面描述的策略用于通配符子路径。

注意classpath*:,当与 Ant-style模式结合使用时,除非实际的目标文件驻留在文件系统中,否则classpath*:只能在模式启动之前可靠地与至少一个根目录一起工作。这意味着,类似classpath*.xml这样的模式可能不会从jar文件的根目录检索文件,而是只从扩展目录的根目录检索文件。

带有类路径的ant样式模式:如果要搜索的根包在多个类路径位置可用,则不能保证资源能够找到匹配的资源。考虑下面的资源位置示例

com/mycompany/package1/service-context.xml

现在考虑某人可能用来尝试找到该文件的Ant样式路径

classpath:com/mycompany/**/service-context.xml

这样的资源可能只在一个位置,但是当使用诸如上一示例的路径尝试对其进行解析时,解析器将根据getResource(“ com / mycompany”)返回的(第一个)URL进行工作。如果此基本包节点存在于多个类加载器位置,则实际的最终资源可能不存在。因此,在这种情况下,您应该使用与ant样式相同的classpath*:,它搜索包含根包的所有类路径位置。

FileSystemResource Caveats

文件系统资源警告

未附加到FileSystemApplicationContext的FileSystemResource(即,当FileSystemApplicationContext不是实际的ResourceLoader时)将按您期望的那样处理绝对路径和相对路径。 相对路径是相对于当前工作目录的,而绝对路径是相对于文件系统的根的。

但是,出于向后兼容性(历史原因)的原因,当FileSystemApplicationContext是ResourceLoader时,这种情况会发生变化。FileSystemApplicationContext强制所有附加的FileSystemResource实例将所有位置路径视为相对路径,不管它们是否以正斜杠开头。在实践中,这意味着下面的例子是等价的

ApplicationContext ctx =    **new** FileSystemXmlApplicationContext("conf/context.xml");
ApplicationContext ctx =
    new FileSystemXmlApplicationContext("/conf/context.xml");

下面的例子也是等价的(尽管它们不同是有意义的,因为一种情况是相对的,另一种情况是绝对的)

FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("some/resource/path/myTemplate.txt");
FileSystemXmlApplicationContext ctx = ...;
ctx.getResource("/some/resource/path/myTemplate.txt");

在实践中,如果您需要真正的绝对文件系统路径,您应该避免将绝对路径与FileSystemResource或FileSystemXmlApplicationContext一起使用,并通过使用file: URL前缀强制使用UrlResource。下面的例子演示了如何做到这一点

// actual context type doesn't matter, the Resource will always be UrlResource
ctx.getResource("file:///some/resource/path/myTemplate.txt");
ApplicationContext ctx =
    new FileSystemXmlApplicationContext("file:///conf/context.xml");

参考文档

你可能感兴趣的:(Spring,Java)