Spring源码学习IOC(1):Resource的分析

IoC容器的初始化流程分析 前言:本文参考了《Spring核心内幕 - 深入解析Spring架构与设计原理(第2版)》一书,结合笔者对源码的阅读得到的关于Spring IoC容器初始化流程的理解。一、什么是控制反转(IoC,Inversion of Control)?    在进入正题之前,首先我们有必要先了解一下控制反转这个概念,“反转”的是什么?为什么要进行控制反转?1.传统的对象依赖关系管理public class M... 阅读详情
我们知道,在spring中,配置文件是通过资源形式加载的,我们首先来分析一些在spring中资源类的结构,并且查看一下资源的类型;

资源类图如下:





  1. public interface InputStreamSource {
  2.         /**
  3.          *用于获得资源的输入流
  4.          */
  5.     InputStream getInputStream() throws IOException;
  6. }
抽象出这层接口,事实上是把java底层的二进制流和spring中的resource给对应以来,把inputstream包装进Resource;



  1. public interface Resource extends InputStreamSource {
  2.     
  3.     boolean exists();
  4.     boolean isOpen();
  5.     
  6.     URL getURL() throws IOException;
  7.     File getFile() throws IOException;
  8.     Resource createRelative(String relativePath) throws IOException;
  9.     String getDescription();
  10. } 
  11.  


进一步抽象出Resource的功能接口,在这里,我们可以看出,在代码编写过程中,接口的设计是根据逻辑一步一步抽象出来的,不用吝啬接口的生成,按照接口隔离原则;
                                                                                                                       

  1. import java.io.File;
  2. import java.io.FileNotFoundException;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.net.URL;

  6. /**
  7.  * Convenience base class for {@link Resource} implementations,
  8.  * pre-implementing typical behavior.
  9.  *
  10.  * <p>The "exists" method will check whether a File or InputStream can
  11.  * be opened; "isOpen" will always return false; "getURL" and "getFile"
  12.  * throw an exception; and "toString" will return the description.
  13.  *
  14.  * @author Juergen Hoeller
  15.  * @since 28.12.2003
  16.  */
  17. public abstract class AbstractResource implements Resource {
  1.     public boolean exists() {
  2.         // Try file existence: can we find the file in the file system?
  3.         try {
  4.             return getFile().exists();
  5.         }
  6.         catch (IOException ex) {
  7.             // Fall back to stream existence: can we open the stream?
  8.             try {
  9.                 InputStream is = getInputStream();
  10.                 is.close();
  11.                 return true;
  12.             }
  13.             catch (Throwable isEx) {
  14.                 return false;
  15.             }
  16.         }
  17.     }
  18.     public boolean isOpen() {
  19.         return false;
  20.     }
  21.     
  22.     public URL getURL() throws IOException {
  23.         throw new FileNotFoundException(getDescription() + " cannot be resolved to URL");
  24.     }
  25.     
  26.     public File getFile() throws IOException {
  27.         throw new FileNotFoundException(getDescription() + " cannot be resolved to absolute file path");
  28.     }
  29.     
  30.     public Resource createRelative(String relativePath) throws IOException {
  31.         throw new FileNotFoundException("Cannot create a relative resource for " + getDescription());
  32.     }
  33.     
  34.     public String getFilename() throws IllegalStateException {
  35.         throw new IllegalStateException(getDescription() + " does not carry a filename");
  36.     }
  37.     public abstract String getDescription();
  38.     public String toString() {
  39.         return getDescription();
  40.     }
  41.     public boolean equals(Object obj) {
  42.         return (obj == this ||
  43.             (obj instanceof Resource && ((Resource) obj).getDescription().equals(getDescription())));
  44.     }
  45.     
  46.     public int hashCode() {
  47.         return getDescription().hashCode();
  48.     }

抽象出来的Resource功能接口对于下面多种不同类型的资源,其有很多功能接口的实现势必是相同的,所以在这里spring建立了一个抽象类,在设计模式中,抽象类应该做到的是,尽量把子类相同的功能方法放到抽象父类中实现,增加复用,而尽量把少的数据推到子类中实现,减少空间的消耗;

                 

在这类Resource中,我们使用得最多的,估计就是要属于ClassPathResource和FileSystemReource;顾名思意,这两种资源类分别是默认在ClassPath和FileSystem下查找资源;而我们用得最多的是classPath,因为这样对工程的移植更有利;


public class FileSystemResource extends AbstractResource {

    private final File file;

    private final String path;

    public FileSystemResource(File file) {
        Assert.notNull(file, "File must not be null");
        this.file = file;
        this.path = StringUtils.cleanPath(file.getPath());
    }

   
    public FileSystemResource(String path) {
        Assert.notNull(path, "Path must not be null");
        this.file = new File(path);
        this.path = StringUtils.cleanPath(path);
    }

    
    public final String getPath() {
        return this.path;
    }


    public boolean exists() {
        return this.file.exists();
    }

    
    public InputStream getInputStream() throws IOException {
        return new FileInputStream(this.file);
    }

    public URL getURL() throws IOException {
        return new URL(ResourceUtils.FILE_URL_PREFIX + this.file.getAbsolutePath());
    }

   
    public File getFile() {
        return file;
    }

    
    public Resource createRelative(String relativePath) {
        String pathToUse = StringUtils.applyRelativePath(this.path, relativePath);
        return new FileSystemResource(pathToUse);
    }

    
    public String getFilename() {
        return this.file.getName();
    }

  
    public String getDescription() {
        return "file [" + this.file.getAbsolutePath() + "]";
    }

    public boolean equals(Object obj) {
        return (obj == this ||
            (obj instanceof FileSystemResource && this.path.equals(((FileSystemResource) obj).path)));
    }

    public int hashCode() {
        return this.path.hashCode();
    }

}


在VStringUtil中,我们可以看见如下代码:

public static String replace(String inString, String oldPattern, String newPattern) {
        if (inString == null) {
            return null;
        }
        if (oldPattern == null || newPattern == null) {
            return inString;
        }

        StringBuffer sbuf = new StringBuffer();
        // output StringBuffer we'll build up
        int pos = 0; // our position in the old string
        int index = inString.indexOf(oldPattern);
        // the index of an occurrence we've found, or -1
        int patLen = oldPattern.length();
        while (index >= 0) {
            sbuf.append(inString.substring(pos, index));
            sbuf.append(newPattern);
            pos = index + patLen;
            index = inString.indexOf(oldPattern, pos);
        }
        sbuf.append(inString.substring(pos));

        // remember to append any characters to the right of a match
        return sbuf.toString();
    }

是将//tihuan成/的代码,我们可见,在这段代码中,对传入的参数进行了严密的验证,正如代码大全中所介绍的防御性编程,我们假定从public传入进来的参数都是不安全的,只有在私有方法中,我们才对传入的参数不进行合法验证;

在这里,我们很明显的看出,代码中使用了适配器模式中的类适配器,在新的接口中,我们用resource接口包装了File,
在新的接口中,我们依然能访问file的isExist方法,却丝毫不知道我们是用的file;
其中,StrigUtils类是一个工具,他对path进行了预处理,处理了如//分解符和.  ..等文件路径描述的特殊操作符
另外的byte等资源,跟bye和ByteInputeStream的关系是类似的,分别是把不同源的数据当作资源,不过ClasspathResource不同的是,你可以传入ClassLoader或者Class来制定当前的类加载器,从而可以确定资源文件的BascDir
如果你不制定classLoader的话和Class的话,那么就会默认是当前线程的ClassLoader,而在这里,PATH和ClassLoader的预处理,都是经过了一个工具类来进行的,可以,在总段代码中,我们看见了很多的复用性和组织性,很多细节的方面的值得我们效仿和学习;
12-Spring架构源码分析-IoC 之装载 BeanDefinitions 总结 前面 从源码层次,分析了 IoC BeanDefinition 装载的整个过程,这篇就这些内容做一个总结将其连贯起来。在前文提过,IoC 容器的初始化过程分为三步骤:Resource 定位、BeanDefinition 的载入和解析,BeanDefinition 注册。整体步骤Resource 定位。我们一般用外部资源来描述 Bean 对象,所以在初始化 IoC 容器的第一步就是需要定位这个外部资源。在上一篇《IoC 之 Spring 统一资源加载策略》已经详细说明了资源加载的过程。... 阅读详情

相关推荐

5-Spring架构源码分析-Spring IOC之 Spring 统一资源加载策略

为Resource接口的默认抽象实现。它实现了Resource接口的大部分的公共实现/***判断文件是否存在,若判断过程产生异常(因为会调用SecurityManager来判断),就关闭对应的流*/@Overridetry{//基于File进行判断}//基于InputStream进行判断try{}}}/***直接返回true,表示可读*/@Override}/***直接返回false,表示未被打开*/@Override。...

Java架狗师知识框架速查表 405

springboot源码解读之配置从哪来

概述 用了一段时间springboot,但对于springboot的配置原理始终不太了解,带着如下疑问学习一下源码: springboot都从哪里读取配置,顺序是什么样的? bean中的属性是怎么注入的? 配置变更时怎么动态修改bean属性? 配置加载 public ConfigurableApplicationContext run(String... args) { St...

hongxingxiaonan的专栏 545

CircuitBreaker Resilience4J 介绍

在分布式环境中,我们的应用可能会面临着各种各样的可恢复的异常(比如超时,网络环境异常),此时我们可以利用不断重试的方式来从异常中恢复(Retry Pattern),使整个集群正常运行。然而,也有一些异常比较顽固,突然发生,无法预测,而且很难恢复,并且还会导致级联失败(举个例子,假设一个服务集群的负载非常高,如果这时候集群的一部分挂掉了,还占了很大一部分资源,整个集群都有可能遭殃)。如果我们这时还是不断进行重试的话,结果大多都是失败的。

zzhongcy的专栏 3539

spring源代码分析(1)--Resource的分析

我们知道,在spring中,配置文件是通过资源形式加载的,我们首先来分析一些在spring中资源类的结构,并且查看一下资源的类型;资源类图如下:public interface InputStreamSource {        /**         *用于获得资源的输入流         */    InputStream getInputStream() throws IOExceptio

浮白 3593

PM1132-220V转5V电源芯片:SOT-23-3封装的高效电源解决方案

在现代电子设备小型化和高效化的趋势下,PM1132芯片凭借其的能力与特性,成为工业控制IoT设备及便携电器的理想电源管理方案。以下从核心技术设计挑战和应用实践展开分析。

M_D13Z476I000l的博客 804

2023年LitCTF web组wp

1、导弹迷踪2、1zjs3、php是世界上最好的语言!!4、Ping5、我Flag呢?7、作业管理系统8、Vim yyds10、这是什么?SQL!注一下!11、Flag点击就送!12、就当无事发生13、彩蛋。

m0_74160536的博客 1587

干货分享:Spring中经常使用的工具类(提示开发效率)

干货分享:Spring中经常使用的工具类(提示开发效率)资源工具类、对象工具类、数组转换、Stream流操作、系统属性解析、集合工具类、AOP代理工具BeanFactory工具类、注解工具类、Bean工具类、数据验证工具类、XML解析工具类、HTML转换工具类,WEB相关工具类

三两肉的博客 1609

电工电子实验——3BIT延时电路的设计与实现

设计一个 3BIT延时电路。 设计分析: Ⅰ.根据触发器的特性,只有来两个触发脉冲时才能恢复到原来的状态。也就是说触发器的输出信号比触发信号延迟了一个触发脉冲周期即1bit。据此3bit就需要3个触发器。 Ⅱ.输出要可控就要加一控制器,可用选择器实现。 Ⅲ.为便于观察输出信号的延迟,可设计一个F1信号。

qq_55543315的博客 1127

Eclipse: “The import java.io cannot be resolved”

Check your Eclipse preferences: Java -> Installed JREs. The one that you’re using should be marked and it should be a JDK not just a JRE. Also check your project’s build path: Right click on the proje

qq_31202403的博客 522

Calibre LVS效率翻倍秘籍:用Hierarchical Flow处理亿级晶体管设计的5个关键阶段

本文详细解析了如何利用Hierarchical Flow技术提升Calibre LVS在亿级晶体管SoC设计中的验证效率。通过五个关键阶段的分层验证流程,包括顶层抽象验证、模块级独立验证等,可显著降低内存占用40-60%,缩短迭代周期50-70%,特别适用于SMIC等先进工艺节点。文章还分享了算力资源优化、并行化处理等实战技巧,帮助工程师应对大规模芯片验证挑战。

sam99的博客 768

【目标跟踪】多目标跟踪的评价工具motmetrics怎么使用?

多目标跟踪,通过motmetrics测试评价对应的视频。

聿默的博客 5367

The import java.io cannot be resolved 问题解决

导入一个新项目后常会出现  The import java.io cannot be resolved  String cannot be resolved to a type  其原因在于没有导入需要的包。 解决办法: 1、选中项目点击右键找到Properties-&gt;java build path-&gt;Libraries-&gt;Add External Jars-&gt;选中本项...

M_Jack的博客 9132

AS7341可见光谱传感器原理图设计,已量产(光线传感器)

最近在做便携式环境光光谱检测项目时,我们基于 ams 的 AS7341 搭了一套硬件电路 —— 这颗芯片算是业内新一代的光谱传感 IC,8 个可见光通道 + NIR + 闪烁检测的配置,加上 6 路并行 16 位 ADC,数据吞吐能力确实够顶。今天就拆解下这个模块的硬件设计细节,聊聊实际做板时的那些考量点。

不脱发的程序猿 639

Spring IoC源码学习:context:component-scan 节点详解

前言 在Spring IoC:parseCustomElement详解中,我们介绍了自定义命名空间节点解析的大部分内容,但是还剩下节点解析的具体过程。本文将以 <context:component-scan />节点为例子,介绍自定义命名空间 context的component-scan节点的解析过程。 正文 首先,我们回到Spring IoC:parseCu...

程序员囧辉 6744

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Spring源码分析(1)-IoC容器的实现

最近在看《Spring技术内幕》这本书学习Spring的技术源码,写博客来记录自己的学习过程。 第一章 这一章主要介绍了Spring的子项目和核心实现、Spring出现的目标。 第二章-IoC容器的实现 控制反转 主动获取依赖的过程:Test对象需要用到Hello属性对象的时候,自己创建一个Hello对象。 public class Hello{ public ...

xjh19970715的博客 243

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Spring原理与源码分析系列(四)- Spring IoC源码分析(上)

0 前言 在上节 Spring原理与源码分析系列(三)- Spring IoC容器启动过程分析(下) 我们已经介绍过,IoC容器主要分为两个阶段:IoC容器启动和依赖注入。 本节内容我们重点将从源码的角度来分析这两个过程,本篇(上)主要分析IoC容器启动过程,而依赖注入部分将放在(下)去分析。 一、IoC容器启动过程 IoC容器启动是由refresh()方法来启动的,这个过程主要分为3个部

noaman_wgs的博客 1270

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

spring源码学习——IOC容器初始化(一)

IOC 容器的初始化包括 BeanDefinition 的 Resource 定位、载入和注册这三个基本的过程。我们以 ApplicationContext 为例讲解,ApplicationContext 系列容器也许是我们最熟悉的,因为 Web项 目 中 使 用 的 XmlWebApplicationContext 就 属 于 这 个 继 承 体 系 , 还 有ClasspathXmlAppli...

努力奔跑 2万+

Spring源码分析之IOC容器的初始化(Resource定位过程)

IOC容器的初始化主要包括三个过程,即 Resource定位过程; BeanDefinition(也就是XML配置文件)的载入; 向IOC容器注册BeanDefinition; Resource定位过程 以FileSystemXmlApplicationContext为例,分析ApplicationContext的实现是怎样完成这个Resource定位过程的。 下面是FileSystem...

sscout的博客 288

Spring IoC源码学习:obtainFreshBeanFactory 详解

Override// 1.为指定BeanFactory创建XmlBeanDefinitionReader// 2.使用此上下文的资源加载环境配置 XmlBeanDefinitionReader// resourceLoader赋值为XmlWebApplicationContext// 3.加载 bean 定义3.加载 bean 定义,。代码块3:loadBeanDefinitions// 1.获取配置文件路径= null) {// 2.根据配置文件路径加载 bean 定义。

2401_84048225的博客 835

Spring源码分析之IOC原理

简介 Spring作为各个大厂面试必问问题,对其了解是必不可少,本文内容是本文在学习Spring的一些总结。本文是SpringIOC文章第一篇,主要介绍IOC各个基础模块与基本概念。 什么是IOC? IOC 英文名字为“控制反转”(Inversion Of control),又称依赖注入(Dependency Injection),这里借用百度百科的描述来解释“Class A中用到了Clas...

apple1414的博客 393

Spring源码阅读之IoC容器初始化1 -- Resource定位

注1:Spring源码基于Spring3.1版本 注2:参考《Spring技术内幕》第二版 1、Spring IoC容器初始化 Spring IoC容器的初始化包括BeanDefinition的Resource定位、载入和注册三个基本过程。在具体分析这三个过程之前,需要注意的是Spring把这三个过程分开,并使用不同的模块来完成,这样使Spring IoC容器更加灵活。

竹叶青的专栏 3104

Spring进阶- Spring IOC实现原理(二)IOC初始化流程

AbstractBeanDefinitionReader的loadBeanDefinitions方法源码如下:这个类并不是加载 xml 的过程,它是创建了一个 Resource 对象,分派 Resource 对象给子类来加载 Bean.@Override// 模式匹配类型的解析器,这种方式是加载多个满足匹配条件的资源try {// 获取到要加载的资源// 委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能= null) {else {

CoFFee________的博客 1229

Spring源码分析——IOC容器

1、IOC容器的概念 理解IOC容器的概念之前首先需要了解依赖翻转(又称依赖倒置)的概念 许多复杂的应用都是通过多个类之间的彼此合作实现业务逻辑的,这使得每个对象都需要管理自己与其合作对象的依赖,而如果这个过程如果交给对象自身实现将会导致代码的耦合度过高。因此出现了依赖反转的概念 依赖反转 将对象间的依赖关系交由框架或者ioc容器实现与维护,从而在降低代码耦合度的同时提高代码的可测试性。这就叫做...

tinysakura的博客 535

Spring IOC和Spring AOP的实现原理(源码主线流程)

写在前面       正本文参考了《spring技术内幕》和spring 4.0.5源码。本文只描述原理流程的主线部分,其他比如验证,缓存什么可以具体参考源码理解。 Spring IOC 一、容器初始化       容器的初始化首先是在对应的构造器中进行,在applicationContext的实现类构造器中,首先对参数路径中的${}进行了处理,用系统变量替换(setConfigL

u013430196的博客 7723

深入研究Spring-IoC:源码分析容器创建

1.前言从之前的分析中可以知道IOC容器的创建大致分为3步:Resource定位、BeanDefinition载入解析、向容器注册BeanDefinition。Tiny-spring手动实现了Spring框架,通过对这个源码的解读可以更好更有效的理解Spring。2.容器创建的硬编码ApplicationContext applicationContext = new ClassPathXmlApp

一支穿云箭 526
上一篇: android:INSTALL_FAILED_INSUFFICIENT_STORAGE解决方法
下一篇: Spring源码学习IOC(2):XmlBeanFactory导读
java_wliang
博客等级 码龄15年 19粉丝 82原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值