IoC之Spring统一资源加载策略

Spring实现了自己的资源加载策略

  • 职能划分,资源的定义和资源的加载要有一个清晰的界限
  • 统一的抽象,统一的资源定义和资源加载策略。

统一的资源:Resource

  • org.springframework.core.io.Resource 为 Spring 框架所有资源的抽象和访问接口,它继承 org.springframework.core.io.InputStreamSource接口。作为所有资源的统一抽象,Resource 定义了一些通用的方法,由子类 AbstractResource 提供统一的默认实现Resource 类图
  • 从上图可以看到,Resource 根据资源的不同类型提供不同的具体实现,如下:

  • FileSystemResource :对 java.io.File 类型资源的封装,只要是跟 File 打交道的,基本上与 FileSystemResource 也可以打交道。支持文件和 URL 的形式,实现 WritableResource 接口,且从 Spring Framework 5.0 开始,FileSystemResource 使用 NIO2 API进行读/写交互。
  • ByteArrayResource :对字节数组提供的数据的封装。如果通过 InputStream 形式访问该类型的资源,该实现会根据字节数组的数据构造一个相应的 ByteArrayInputStream。
  • UrlResource :对 java.net.URL类型资源的封装。内部委派 URL 进行具体的资源操作。
  • ClassPathResource :class path 类型资源的实现。使用给定的 ClassLoader 或者给定的 Class 来加载资源。
  • InputStreamResource :将给定的 InputStream 作为一种资源的 Resource 的实现类

统一的资源加载:ResourceLoader

  • ResourceLoader提供了统一的抽象,具体的实现由相应的子类来负责实现,类结构图如下:ResourceLoader 类图
  • ResourceLoader 中最核心的方法是:
    Resource getResource(String location);
  • DefaultResourceLoader对getResource提供了默认实现,代码如下:
    @Override
    public Resource getResource(String location) {
       Assert.notNull(location, "Location must not be null");
    
       for (ProtocolResolver protocolResolver : this.protocolResolvers) {
          Resource resource = protocolResolver.resolve(location, this);
          if (resource != null) {
             return resource;
          }
       }
       // 如果是"/"开头, 那么就通过ClassPathContextResource 
       if (location.startsWith("/")) {
          return getResourceByPath(location);
       }
       else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
       //如果以classpath为开头,那么就通过ClassPathResource
          return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
       }
       //然后,根据是否为文件 URL ,是则返回 FileUrlResource 类型的资源,否则返回 UrlResource 类型的资源
       else {
          try {
             // Try to parse the location as a URL...
             URL url = new URL(location);
             return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
          }
          catch (MalformedURLException ex) {
             // No URL -> resolve as resource path.
             return getResourceByPath(location);
          }
       }
    }
    protected Resource getResourceByPath(String path) {
       return new ClassPathContextResource(path, getClassLoader());
    }
    public ClassPathResource(String path, @Nullable ClassLoader classLoader) {
       Assert.notNull(path, "Path must not be null");
       String pathToUse = StringUtils.cleanPath(path);
       if (pathToUse.startsWith("/")) {
          pathToUse = pathToUse.substring(1);
       }
       this.path = pathToUse;
       this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
    }
    protected Resource getResourceByPath(String path) {
       return new ClassPathContextResource(path, getClassLoader());
    }
  • ResourceLoader的getResource(String location)每次只能根据location返回一个Resource资源,当需要加载多个资源的时候,就可以使用ResourcePartternResolver,它支持根据指定的资源路径匹配模式每次返回多个Resource实例

小结:

  • Spring 提供了 Resource 和 ResourceLoader 来统一抽象整个资源及其定位。使得资源与资源的定位有了一个更加清晰的界限,并且提供了合适的 Default 类,使得自定义实现更加方便和清晰。
  • AbstractResource 为 Resource 的默认抽象实现,它对 Resource 接口做了一个统一的实现,子类继承该类后只需要覆盖相应的方法即可,同时对于自定义的 Resource 我们也是继承该类。
  • DefaultResourceLoader 同样也是 ResourceLoader 的默认实现,在自定 ResourceLoader 的时候我们除了可以继承该类外还可以实现 ProtocolResolver 接口来实现自定资源加载协议。
  • DefaultResourceLoader 每次只能返回单一的资源,所以 Spring 针对这个提供了另外一个接口 ResourcePatternResolver ,该接口提供了根据指定的 locationPattern 返回多个资源的策略。其子类 PathMatchingResourcePatternResolver 是一个集大成者的 ResourceLoader ,因为它即实现了 Resource getResource(String location) 方法,也实现了 Resource[] getResources(String locationPattern) 方法。

ps:该文为芋道源码学习笔记

转载于:https://my.oschina.net/u/4055223/blog/3098311

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值