Spring源码学习6:BeanDefinitionRegister模块-ReourceLoader

BeanDefinition是怎么来的?

ReourceLoader装载配置文件
BeanDefinitionReader解析配置信息
配置文件
Resource
BeanDefinitionRegister
BeanDefinition

发现流程图中涉及到了4个主要的接口,齐心协力之下,把配置信息变成了我们熟悉的Bean定义,来学习一下吧:

  • ReourceLoader:用于加载资源(如XML配置文件)
  • Resource: 表示加载的资源
  • BeanDefinitionReader:读取资源中的bean定义
  • BeanDefinitionRegistry:用于注册和管理bean定义

在上一篇文章中,我们学习了Resource接口,知道了可以通过实现类的构造方法来获取一个Resource对象从而对资源进行访问。今天我们学习一下怎么通过ResourceLoader接口来获取Ressource对象。

问题:ResourceLoader 得到Resource对象和使用Resource构造函数来得到Resource对象有什么不同,ResourceLoader 的优势在哪儿?

资源加载器:ReourceLoader

ResourceLoader 是 Spring 框架中的一个接口,定义了一个加载资源的策略。它提供了一种统一的方式来访问各种不同类型的资源,例如文件系统中的文件、类路径资源、URL 资源等。

ResourceLoader 接口源码

public interface ResourceLoader {

    String CLASSPATH_URL_PREFIX = "classpath:";

	根据资源的路径获取资源对象
    Resource getResource(String location);

	返回用于加载类的ClassLoader
    ClassLoader getClassLoader();
}

ResourceLoader 使用案例

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.DefaultResourceLoader;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class ResourceLoaderExample {

    public static void main(String[] args) {
        ResourceLoader resourceLoader = new DefaultResourceLoader();

        // 加载类路径资源
        Resource classPathResource = resourceLoader.getResource("classpath:config.properties");
        printResourceContent(classPathResource);

        // 加载文件系统资源
        Resource fileSystemResource = resourceLoader.getResource("file:/path/to/file.txt");
        printResourceContent(fileSystemResource);

        // 加载 URL 资源
        Resource urlResource = resourceLoader.getResource("http://example.com/resource.txt");
        printResourceContent(urlResource);
    }

    private static void printResourceContent(Resource resource) {
        try (InputStream inputStream = resource.getInputStream();
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

我们发现,不管访问什么类型的资源,都可以通过getResource()方法实现,该方法会通过入参的不同前缀(classpath:file:http:)来选择使用正确的Resource实现类(),这就是统一接口

resourceLoader.getResource 策略模式

public class DefaultResourceLoader implements ResourceLoader {

    @Override
    public Resource getResource(String location) {
        Assert.notNull(location, "Location must not be null");
        
        // 处理前缀
        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 {
                // 尝试将位置解析为URL
                URL url = new URL(location);
                return new UrlResource(url);
            } catch (MalformedURLException ex) {
                // 不是URL, 那么就作为文件路径
                return getResourceByPath(location);
            }
        }
    }

	如果getResource()入参没有“前缀”,默认使用文件系统资源
    protected Resource getResourceByPath(String path) {
        return new FileSystemResource(path);
    }

    @Override
    @Nullable
    public ClassLoader getClassLoader() {
        return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
    }
}

看来DefaultResourceLoader只支持三种类型资源:文件系统资源、类路径资源、URl资源

问题:ResourceLoader 得到Resource对象和使用Resource构造函数来得到Resource对象有什么不同,ResourceLoader 的优势在哪儿?
答案:
Resource需要自己选择实现类,而通过ResourceLoader可以通过策略者模式,根据前缀选择合适的算法,适合加载多种资源类型的场景。如果没有前缀默认使用文件系统资源来获取Resource。

相比Resource自己选择实现类,ResourceLoader优势:

  • 统一接口:提供一个统一的接口来加载不同类型的资源。
  • 高度扩展性:可以通过自定义实现来支持更多类型的资源。
  • 便捷性:内置了处理类路径资源、文件系统资源和 URL 资源的能力,适用于大多数常见的场景。

ResourceLoader 常用实现类

DefaultResourceLoader
默认实现类,能够处理各种资源位置前缀,如classpath:、file:、http:等。
FileSystemResourceLoader
扩展DefaultResourceLoader,用于加载文件系统中的资源。
ServletContextResourceLoader
用于在 Web 环境中加载资源,资源路径相对于 Web 应用的根目录。
WebApplicationContext
扩展自ApplicationContext,它也是一个ResourceLoader,能够加载Web应用环境中的资源。

ResourceLoader 为什么已经有DefaultResourceLoader,还会有一个FileSystemResourceLoader

 
不同点及使用场景:

  1. DefaultResourceLoader

    • 多用途:适用于需要加载多种类型资源的场景。通过前缀可以方便地指定资源类型。
    • 自动解析:可以根据前缀自动选择合适的 Resource 实现类,简化了资源加载代码。
    • 可扩展性:能够扩展以支持更多类型的资源。
  2. FileSystemResourceLoader

    • 专用性:适用于只需要加载文件系统资源的场景。它避免了不必要的类型检查和解析。
    • 简化实现:因为只处理文件系统资源,代码更为简洁。

其实DefaultResourceLoader、FileSystemResourceLoader主要还是看我们怎么使用,如果是多种资源类型的加载,就使用DefaultResourceLoader,如果只是针对文件系统的资源加载,使用FileSystemResourceLoader更加简介。

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值