Spring资源管理,Spring资源管理源码分析

news2024/9/19 10:42:18

文章目录

  • 一、Java标准资源管理
    • 1、Java 标准资源定位
    • 2、Java URL 协议扩展
      • 基于 java.net.URLStreamHandlerFactory
      • 基于 java.net.URLStreamHandler
    • 3、Java 标准资源管理扩展的步骤
    • 4、Spring为什么不用Java标准的资源管理
  • 二、Spring资源接口与实现
    • 1、Spring基本资源接口
      • InputStreamSource接口
      • Resource接口
      • WritableResource接口
      • EncodedResource类
      • ContextResource接口
    • 2、Spring 内建 Resource 实现
      • BeanDefinitionResource
      • ByteArrayResource
      • ClassPathResource
      • FileSystemResource
    • 3、Spring Resource 接口扩展
      • 可写资源接口
      • 编码资源接口
    • 4、Spring 资源加载器
    • 5、Spring 通配路径资源加载器
      • Spring 通配路径资源扩展
  • 三、依赖注入Spring Resource
  • 四、依赖注入 ResourceLoader
  • 参考资料

一、Java标准资源管理

1、Java 标准资源定位

职责说明
面向资源文件系统、artifact(jar、war、ear 文件)以及远程资源(HTTP、FTP等)
API 整合java.lang.ClassLoader#getResource、java.io.File 或 java.net.URL
资源定位java.net.URL 或 java.net.URI
面向流式存储java.net.URLConnection
协议扩展java.net.URLStreamHandler 或 java.net.URLStreamHandlerFactory

2、Java URL 协议扩展

基于 java.net.URLStreamHandlerFactory

在这里插入图片描述
java.net.URL中定义了一个静态变量factory:

static URLStreamHandlerFactory factory;

public static void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) {
    synchronized (streamHandlerLock) {
        if (factory != null) { // 只能设置一次
            throw new Error("factory already defined");
        }
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkSetFactory();
        }
        handlers.clear();
        factory = fac;
    }
}

基于 java.net.URLStreamHandler

基于 java.net.URLStreamHandler 扩展协议(JDK 1.8 內建协议实现):

协议实现类
filesun.net.www.protocol.file.Handler
ftpsun.net.www.protocol.ftp.Handler
httpsun.net.www.protocol.http.Handler
httpssun.net.www.protocol.https.Handler
jarsun.net.www.protocol.jar.Handler
mailtosun.net.www.protocol.mailto.Handler
netdocsun.net.www.protocol.netdoc.Handler

实现类名必须为 “Handler”:

实现类命名规则说明
默认sun.net.www.protocol.${protocol}.Handler
自定义通过 Java Properties java.protocol.handler.pkgs 指定实现类包名,实现类名必须为“Handler”。如果存在多包名指定,通过分隔符 “|”

java.net.URL中定义protocolPathProp:

private static final String protocolPathProp = "java.protocol.handler.pkgs";


static URLStreamHandler getURLStreamHandler(String protocol) {

     URLStreamHandler handler = handlers.get(protocol);
     if (handler == null) {

         boolean checkedWithFactory = false;

         // Use the factory (if any)
         if (factory != null) {
             handler = factory.createURLStreamHandler(protocol);
             checkedWithFactory = true;
         }

         // Try java protocol handler
         if (handler == null) { // 对protocolPathProp 的处理
             String packagePrefixList = null;

             packagePrefixList
                 = java.security.AccessController.doPrivileged(
                 new sun.security.action.GetPropertyAction(
                     protocolPathProp,""));
             if (packagePrefixList != "") {
                 packagePrefixList += "|";
             }

             // REMIND: decide whether to allow the "null" class prefix
             // or not.
             packagePrefixList += "sun.net.www.protocol";

             StringTokenizer packagePrefixIter =
                 new StringTokenizer(packagePrefixList, "|");

3、Java 标准资源管理扩展的步骤

(1)简易实现
实现 URLStreamHandler 并放置在 sun.net.www.protocol.${protocol}.Handler 包下

(2)自定义实现
• 实现 URLStreamHandler
• 添加 -Djava.protocol.handler.pkgs 启动参数,指向 URLStreamHandler 实现类的包下

(3)高级实现
• 实现 URLStreamHandlerFactory 并传递到 URL 之中

4、Spring为什么不用Java标准的资源管理

Java 标准资源管理强大,然而扩展复杂,资源存储方式并不统一。

而使用Java开发的程序员,基本也都离不开Spring,作为Java届的龙头老大,Spring的很多东西都要试图与Java比一比,很多东西都完全独立于jdk自己重新弄了一套。

这个操作,Spring似乎实现的很成功,甚至隐隐超过jdk默认的很多实现,有一种引领java开发的潮流的意思。

二、Spring资源接口与实现

1、Spring基本资源接口

资源接口:

类型接口
输入流org.springframework.core.io.InputStreamSource
只读资源org.springframework.core.io.Resource
可写资源org.springframework.core.io.WritableResource
编码资源org.springframework.core.io.support.EncodedResource
上下文资源org.springframework.core.io.ContextResource

InputStreamSource接口

InputStreamSource接口只有一个方法,getInputStream获取输入流。

public interface InputStreamSource {

	InputStream getInputStream() throws IOException;
}

Resource接口

Resource只读资源,继承了InputStreamSource接口,也具有获取输入流功能。同时具有getURL、getURI、getFile等功能,对资源只提供读取功能的接口。

WritableResource接口

WritableResource可写资源,继承Resource,有isWritable来判断资源是否可写,同时可以getOutputStream获取输出流。

EncodedResource类

EncodedResource类用于编码,继承InputStreamSource,针对需要指定资源编码如UTF-8这种的资源。属性有Resource对象,主要通过getInputStreamReader来实现编码。

ContextResource接口

ContextResource接口继承了Resource接口,ContextResource应用较少,上下文资源,一般给Servlet引擎使用。。

2、Spring 内建 Resource 实现

资源来源资源协议实现类
Bean 定义org.springframework.beans.factory.support.BeanDefinitionResource
数组无 org.springframework.core.io.ByteArrayResource
类路径classpath:/org.springframework.core.io.ClassPathResource
文件系统file:/org.springframework.core.io.FileSystemResource
URLURL 支持的协议org.springframework.core.io.UrlResource
ServletContextorg.springframework.web.context.support.ServletContextResource

BeanDefinitionResource

实际上这个类很少用到。

它是不可读的,主要用于描述。

ByteArrayResource

内存型的资源流,同java.io.ByteArrayInputStream

ClassPathResource

它是用class、classLoader进行资源的读取的。

FileSystemResource

3、Spring Resource 接口扩展

可写资源接口

org.springframework.core.io.WritableResource

  • org.springframework.core.io.FileSystemResource
  • org.springframework.core.io.FileUrlResource(@since 5.0.2)
  • org.springframework.core.io.PathResource(@since 4.0 & @Deprecated)

编码资源接口

org.springframework.core.io.support.EncodedResource

// 代码实例
String currentJavaFilePath = "D:\\test.text";
File currentJavaFile = new File(currentJavaFilePath);
// FileSystemResource => WritableResource => Resource
FileSystemResource fileSystemResource = new FileSystemResource(currentJavaFilePath);
EncodedResource encodedResource = new EncodedResource(fileSystemResource, "UTF-8");
// 字符输入流
try (Reader reader = encodedResource.getReader()) {
    System.out.println(IOUtils.toString(reader));
}

4、Spring 资源加载器

org.springframework.core.io.ResourceLoader

  • org.springframework.core.io.DefaultResourceLoader
    • org.springframework.core.io.FileSystemResourceLoader
    • org.springframework.core.io.ClassRelativeResourceLoader
    • org.springframework.context.support.AbstractApplicationContext

AbstractApplicationContext是应用上下文的实现,所以说spring应用上下文也是一种资源加载器。

String currentJavaFilePath = "/D:\\test.text"; // 以 / 开头
// 新建一个 FileSystemResourceLoader 对象
FileSystemResourceLoader resourceLoader = new FileSystemResourceLoader();
// FileSystemResource => WritableResource => Resource
Resource resource = resourceLoader.getResource(currentJavaFilePath);
EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
// 字符输入流
try (Reader reader = encodedResource.getReader()) {
    System.out.println(IOUtils.toString(reader));
}

5、Spring 通配路径资源加载器

通配路径 ResourceLoader:

  • org.springframework.core.io.support.ResourcePatternResolver
    • org.springframework.core.io.support.PathMatchingResourcePatternResolver

路径匹配器:

  • org.springframework.util.PathMatcher
    • Ant 模式匹配实现 - org.springframework.util.AntPathMatcher

Spring 通配路径资源扩展

public interface ResourceUtils {

    static String getContent(Resource resource) {
        try {
            return getContent(resource, "UTF-8");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    static String getContent(Resource resource, String encoding) throws IOException {
        EncodedResource encodedResource = new EncodedResource(resource, encoding);
        // 字符输入流
        try (Reader reader = encodedResource.getReader()) {
            return IOUtils.toString(reader); // org.apache.commons.io.IOUtils
        }
    }
}

(1)实现 org.springframework.util.PathMatcher
(2)重置 PathMatcher:PathMatchingResourcePatternResolver#setPathMatcher

public class CustomizedResourcePatternResolverDemo {

    public static void main(String[] args) throws IOException {
        // 读取当前 package 对应的所有的 .java 文件
        // *.java
        String currentPackagePath = "/D:\\";
        String locationPattern = currentPackagePath + "*.java";
        PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(new FileSystemResourceLoader());

        resourcePatternResolver.setPathMatcher(new JavaFilePathMatcher());

        Resource[] resources = resourcePatternResolver.getResources(locationPattern);

        Stream.of(resources).map(ResourceUtils::getContent).forEach(System.out::println);
    }

    static class JavaFilePathMatcher implements PathMatcher {

        @Override
        public boolean isPattern(String path) {
            return path.endsWith(".java");
        }

        @Override
        public boolean match(String pattern, String path) {
            return path.endsWith(".java");
        }

        @Override
        public boolean matchStart(String pattern, String path) {
            return false;
        }

        @Override
        public String extractPathWithinPattern(String pattern, String path) {
            return null;
        }

        @Override
        public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
            return null;
        }

        @Override
        public Comparator<String> getPatternComparator(String path) {
            return null;
        }

        @Override
        public String combine(String pattern1, String pattern2) {
            return null;
        }
    }
}

三、依赖注入Spring Resource

基于 @Value 实现,如:

@Value(“classpath:/...)
private Resource resource;

通常 Resource 无法通过依赖查找,可以通过@Value来配合依赖注入,它们属于内部依赖对象,非常规的 Bean 生命周期管理。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.io.Resource;
import javax.annotation.PostConstruct;
import java.util.stream.Stream;

/**
 * 注入 {@link Resource} 对象示例,ResourceUtils在上面有
 *
 * @see Resource
 * @see Value
 * @see AnnotationConfigApplicationContext
 * @since
 */
public class InjectingResourceDemo {

    // 注入default.properties资源
    @Value("classpath:/META-INF/default.properties")
    private Resource defaultPropertiesResource;

    // 注入所有的properties资源
    // classpath*:/ 表示所有 ClassPath 下的资源,相当于 ClassLoader#getResources 方法
    // classpath:/ 表示当前 ClassPath 下的资源,相当于 ClassLoader#getResource 方法
    @Value("classpath*:/META-INF/*.properties")
    private Resource[] propertiesResources;

    // 获取Environment参数
    @Value("${user.dir}")
    private String currentProjectRootPath;

    @PostConstruct
    public void init() {
        System.out.println(ResourceUtils.getContent(defaultPropertiesResource));
        System.out.println("================");
        Stream.of(propertiesResources).map(ResourceUtils::getContent).forEach(System.out::println);
        System.out.println("================");
        System.out.println(currentProjectRootPath);
    }

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 注册当前类作为 Configuration Class
        context.register(InjectingResourceDemo.class);
        // 启动 Spring 应用上下文
        context.refresh();
        // 关闭 Spring 应用上下文
        context.close();

    }
}

四、依赖注入 ResourceLoader

方法一:实现 ResourceLoaderAware 回调
方法二:@Autowired 注入 ResourceLoader
方法三:注入 ApplicationContext 作为 ResourceLoader

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import javax.annotation.PostConstruct;
import java.util.stream.Stream;

/**
 * 注入 {@link ResourceLoader} 对象示例
 *
 * @see ResourceLoader
 * @see Resource
 * @see Value
 * @see AnnotationConfigApplicationContext
 * @since
 */
public class InjectingResourceLoaderDemo implements ResourceLoaderAware {

    private ResourceLoader resourceLoader; // 方法一

    @Autowired
    private ResourceLoader autowiredResourceLoader; // 方法二

    @Autowired
    private AbstractApplicationContext applicationContext; // 方法三

    @PostConstruct
    public void init() {
        System.out.println("resourceLoader == autowiredResourceLoader : " + (resourceLoader == autowiredResourceLoader));// true
        System.out.println("resourceLoader == applicationContext : " + (resourceLoader == applicationContext)); // true
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public static void main(String[] args) {

        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        // 注册当前类作为 Configuration Class
        context.register(InjectingResourceLoaderDemo.class);
        // 启动 Spring 应用上下文
        context.refresh();
        // 关闭 Spring 应用上下文
        context.close();

    }
}

参考资料

极客时间-《小马哥讲 Spring 核心编程思想》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/165869.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ 简单实现RPC网络通讯

RPC是远程调用系统简称&#xff0c;它允许程序调用运行在另一台计算机上的过程&#xff0c;就像调用本地的过程一样。RPC 实现了网络编程的“过程调用”模型&#xff0c;让程序员可以像调用本地函数一样调用远程函数。最近在做的也是远程调用过程&#xff0c;所以通过重新梳理R…

项目管理平台,如何助力CMMI3-5级高效落地?

近日CoCode旗下Co-ProjectV3.0智能项目管理平台全面升级&#xff0c;CoCode产品4大版本全新发布&#xff0c;用户不限版本30天免费试用&#xff1b;平台全面支持CMMI3-5级&#xff0c;助力CMMI高效落地。 一、4大版本全新发布 不限版本30天免费试用 Co-Project V3.0智能项目管理…

FPGA:组合逻辑电路的设计

文章目录组合逻辑电路的设计组合逻辑电路的设计步骤组合逻辑电路的设计举例例1例2组合逻辑电路的设计 根据实际逻辑问题&#xff0c;求出所要求逻辑功能的最简单逻辑电路。 组合逻辑电路的设计步骤 1.逻辑抽象&#xff1a;根据实际逻辑问题的因果关系确定输入、输出变量&…

【寒假每日一题】DAY8 倒置字符串

牛客网链接&#xff1a;传送门 【❤️温馨提示】自己做一遍&#xff0c;再看解析效果更佳哟 描述 将一句话的单词进行倒置&#xff0c;标点不倒置。输入描述&#xff1a; 每个测试输入包含1个测试用例&#xff1a; I like beijing. 输入用例长度不超过100输出描述&#xff1a…

Open3D 点云投影至指定平面(Python版本)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 假设给定的平面为 a x + b y + c z + 1 = 0 ax+by+cz+1=0

Python基础(二十四):面向对象核心知识

文章目录 面向对象核心知识 一、面向对象三大特性 1、封装 2、继承 3、多态

音频音量调整中的ramp up down

在日常生活中不管是打电话还是听音乐&#xff0c;都会遇到音量不合适而去调整音量的情况。如果音量调整软件处理不好&#xff0c;就会听到pop noise。产生pop noise的原因是音量直接从当前值骤变到目标值&#xff0c;而不是缓慢的变。如果缓慢的变就不会有pop noise了。图1显示…

select for update是行锁还是表锁,还真得看情况

背景 看到许多写select for update是行锁还是表锁的文章&#xff0c;但每篇文章的结论好像都不太一样。同时&#xff0c;是行锁还是表锁的问题直接影响着系统的性能&#xff0c;所以特意为大家调研一番&#xff0c;也就有了本篇文章&#xff0c;一共为大家汇总验证了20个场景下…

MES系统选型攻略,优秀MES系统应具备哪些性质

在众多MES系统中&#xff0c;企业怎样才能找到最适合自己的产品&#xff1f;那么&#xff0c;一套高质量的MES系统&#xff0c;究竟有什么特点&#xff1f;随着全球经济一体化的发展&#xff0c;中美两国之间的贸易战争日趋白热化&#xff0c;中国作为一个生产大国&#xff0c;…

行为型模式 - 迭代器模式iterator

模式的定义与特点 迭代器模式&#xff08;iterator Pattern&#xff09;&#xff0c;为的提是可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起形成的总体称之为聚集&#xff0c;聚集对象是能够包容一组对象的容器对象。迭代子模式将迭代逻辑封装到一个…

ffmpeg源码编译vs2013版本

完整版安装ffmpeg 一、安装choco 1.Set-ExecutionPolicy AllSigned 2.Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.N…

链队基本操作(笔记版)

本节主要针对链栈的基本操作进行解析。 # coding:___utf-8___ # author:Guoxuan Sun time:2023/1/12 #链栈的基本操作 #链栈的创建与顺序栈的区别就是每个结点都有一个指针域 #同时链栈也是有两个指针front和rear #链栈中的front指针指向的结点是第一个结点&#xff0c;不是空…

关于MySQL中的存储引擎

存储引擎&#xff1a;&#xff08;了解内容&#xff09; 1、什么是存储引擎&#xff0c;有什么用&#xff1f; 存储引擎是mysql中特有的一个术语&#xff0c;其他数据库中没有。 存储引擎就是一个表存储/组织数据的方式。不同的存储引擎&#xff0c;表存储数据的方式不同。 目前…

基于Androidstudio的宠物交友app

需求信息&#xff1a; 客户端&#xff1a; 1&#xff1a;登录注册&#xff1a;用户可以通过自己的信息进行账号的注册 2&#xff1a;宠物信息&#xff1a;列表显示发布的宠物想&#xff0c;可以通过条件对宠物信息进行筛选&#xff0c;以及沟通意向点亮 3&#xff1a;宠物圈&am…

java调用python文件的几种方式

java调用python的契机来自于一个项目需要用到算法&#xff0c;但是算法工程师们写的python&#xff0c;于是就有了java后端调用python脚本的需求&#xff0c;中间遇到了许多问题&#xff0c;特此记录整理了一次。1、java调用python的方式有哪几种1.1 方法一&#xff1a;jpython…

选择排序.

一、简单选择排序 void select_sort(int a[], int len){ //len为数组长度for (int i 0; i < len-1; i){//n个数需要比较n-1趟int min i;//记录最小值的位置for (int j i1; j < len-1; j){if (a[j] < a[min]) min j;//更新最小值的位置} if (min ! i) swap(a[i], …

vue3 项目篇商场 之 初始化项目

目录vue3 项目篇商场 之 初始化项目1&#xff1a;安装 rem 适配src 同级目录下创建 postcss.config.jsmain.ts2 :使用字体图标加字体图标 &#xff08; Symbol 这个选项&#xff09;public / index.html使用效果3 sass4&#xff1a;vant3引入 按需引入 ( 非 vite )4-1 babel.co…

2022年,开源社最亮的星

开源社成立于 2014 年&#xff0c;是由志愿贡献于开源事业的个人成员&#xff0c;依 “贡献、共识、共治” 原则所组成&#xff0c;始终维持厂商中立、公益、非营利的特点&#xff0c;是最早以 “开源治理、国际接轨、社区发展、开源项目” 为使命的开源社区联合体。本次年度评…

常用的专业数据恢复软件有哪些?恢复数据就看这10个!

互联网时代&#xff0c;我们都习惯使用电脑来进行办公&#xff0c;电脑里面都保存着我们很多数据。数据的日积月累&#xff0c;会导致电脑的运行速度减缓&#xff0c;为此我们都会定期对电脑进行清理。 如果在清理过程中&#xff0c;不小心误删或者格式化了数据&#xff0c;有…

漏洞挖掘之信息收集

简介 对单一指定目标网站进行黑盒测试&#xff0c;最重要的就是信息收集&#xff0c;因为网站管理员肯定会在用户经常访问的主网站进行经常维护&#xff0c;而那些子域名&#xff0c;没有什么人访问的&#xff0c;可能就会忘记维护&#xff0c;挖洞的突破点大都在于子域名上&am…