Spring(二):容器的实现——配置文件封装与加载Bean过程

那么究竟这个ClassPathResource完成了什么功能

ClassPathResource实现的就是加载配置文件的功能,并且Spring实现了自己的资源加载策略,不妨可以试想一下,如果没有自己的资源加载策略,对于各种形式的文件,比如file、jar、xml等形式,需要怎样进行解析加载呢?所以,Spring干脆对其内部使用到的资源实现了自己的抽象结构

而这个资源加载策略、抽象结构的关键在于两个接口

  • InputStreamSource

  • Resource

InputStreamSource

在这里插入图片描述

可以看到这个接口十分简单,里面只定义了一个获取InputStream流的方法,用于获取文件的InputStream

Resource

在这里插入图片描述

在这里插入图片描述

从源码上就可以看到Resource接口继承了InputStreamSource接口,所以具体的配置文件抽象结构就是Resource接口

相当于Resource接口抽象了所有Spring内部将会使用到的底层资源,一个Resource对应就是一个资源,是File类型的、还是URL类型的、是否存在、是否可读、最近的修改时间等,都可以从这个抽象接口中获取,从这个接口就可以获取配置文件的资源

所以,针对不同资源类型的(File、Url、ClassPath等),对应都会有一个Resource实现类!

在这里插入图片描述

可以看到这个Resource家族是很大的!

下面列举几个常用的

  • FileSystemResource:获取File资源

  • ClassPathResource:获取ClassPath资源

  • UrlResource:获取URL资源

  • InputStreamResource:获取InputStream资源

  • ByteArrayResource:获取Byte数组资源

有了Resource接口,我们就可以对所有资源文件进行统一处理了,每个资源文件就是一个Resource

Resource相关实现类对配置文件进行封装了之后,后面XmlBeanFactory对文件的读取工作就全部交给了XmlBeanDefinitionReader来处理了

在这里插入图片描述

在这里插入图片描述

可以看到,构造方法就是将传进来的Resource交由XmlBeanDefinitionReader去进行处理,调用的是loadBeanDefinitions方法,也就是说,this.reader.loadBeanDefinitionReader(Resource)才是资源加载的真正实现!

所以,从配置文件的读取,要从这里开始

这里要注意的一点是,XmlBeanFactory还调用了super(ParentBeanFactory方法),而XmlBeanFactory的父类是DefaultListableBeanFactory

在这里插入图片描述

可以看到,DefaultListableBeanFactory又直接super,其父类是AbstractAutowireCapableBeanFactory

在这里插入图片描述

可以看到,进来先调用AbstractAutowireCapableBeanFactory的无参构造方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

无参构造中值得注意的是ignoreDependencyInterface方法,该方法的主要作用是忽略给定接口的自动装配功能,也就是说实现了这些接口的类都不会再有自动注入功能,其底层实现是将忽略的接口存进名为ignoreDependencyInterfaces的HashSet集合中

举个栗子,假如一个实体A中的成员属性是实体B,当实体A进行自动注入的时候,实体B也会被自动实例化,这也是Spring中提供的一个重要特性,但有些时候,我们不希望成员实体被自动注入那么我们可以让成员实体B去实现BeanNameAware接口、BeanFactoryAware接口、BeanClassLoaderAware接口,但前提是,实体A必须要有B的setter方法,也就是外部注入方法是不支持的!(这也可能是官方推荐setter方法注入原因之一)

对于aware这类接口,其实还有一个重要的作用是让bean对容器有意识,一般来说,bean是根本不知道Spring的IOC容器的,所以Bean是无法获取Spring的IOC容器服务的,为了让Bean对Spring的IOC容器有意识,所以我们可以让实体去实现上面的那些aware接口,这样在容器里面的这些Bean会意识到IOC容器,并且可以获取相对应的IOC容器服务,比如实现BeanNameAware接口,可以让Bean获取自己在IOC容器里面的Name

但这里还不能理解,为什么要给这些接口忽略外部注入功能???

这里我猜测,可能是想不让Bean被外部有意识的Bean污染(setter注入),本来Bean就是一个无意识的东西,假如Bean还能注入外部有意识的Bean,那么就会越来越多的Bean对Spring的IOC容器有意识,违反了初衷

加载Bean

现在已经对配置文件进行封装了,那么下面就可以来加载Bean了

加载Bean的时候,其实是在读取配置文件里面完成的,也就是下面这句代码

在这里插入图片描述

这一整套流程是比较复杂的

EncodedResource

首先是封装资源文件后,对文件Resource进行EncodedResource封装

在这里插入图片描述

这个类是对文件的编码进行处理的

在这里插入图片描述

可以看到其构造器,其实起到装配作用而已,比如装配了文件Resource,定义了编码encoding和字符集charset,其主要作用体现在getReader方法上

不过先科普一下字符集和编码的关系,编码是依赖于字符集的,比如UTF-8编码就依赖于Unicode字符集,一般来说一个字符集对应一种编码

public Reader getReader() throws IOException {

//判断字符集是否为空,如果不为空,根据字符集处理文件并返回InputStreamReader

//并且优先判断字符集

if (this.charset != null) {

return new InputStreamReader(this.resource.getInputStream(), this.charset);

}

//判断编码是否为空,如果字符集不存在,那么就根据编码处理文件并返回InputStreamReader

else if (this.encoding != null) {

return new InputStreamReader(this.resource.getInputStream(), this.encoding);

}

//如果即没有编码,也没有字符集,默认方式处理文件返回InputStreamReader,默认为UTF-8编码

//从下面的源码中可以看出来

else {

return new InputStreamReader(this.resource.getInputStream());

}

}

![在这里插入图片描述](https://img-blog.csdnimg.cn/80acc79176984de2823a88693b09baa2.png?x-oss-proces
作者私人号:vip1024c
s=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAR0RVVF9FbWJlcg==,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)

loadBeanDefinitions方法

使用了EncodedResource对文件进行编码处理了之后,接下来就调用重载的loadBeanDefinitions,相当于将编码后的Resource交给重载的loadBeanDefinitions方法处理,具体根据配置文件去加载Bean的操作都在这个方法里面

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {

//空判断

Assert.notNull(encodedResource, “EncodedResource must not be null”);

//开启日志追踪

if (logger.isTraceEnabled()) {

logger.trace("Loading XML bean definitions from " + encodedResource);

}

//从当前线程的ThreadLocal去获取正在加载的Resource

Set currentResources = this.resourcesCurrentlyBeingLoaded.get();

//下面这个判断,是用来防止循环加载的!

//因为currentResource是一个HashSet集合,重复的不会进行添加

//所以,往currentResources添加失败,就表明当前文件已经在加载了

if (!currentResources.add(encodedResource)) {

throw new BeanDefinitionStoreException(

“Detected cyclic loading of " + encodedResource + " - check your import definitions!”);

}

//获取文件的InputStream

try (InputStream inputStream = encodedResource.getResource().getInputStream()) {

//又封装了一层,封装为了不是Spring下的InputResource

InputSource inputSource = new InputSource(inputStream);

//同样进行编码操作

//所以可以估计,Spring所说的自定义文件加载策略,其实就是基于InputResource的

if (encodedResource.getEncoding() != null) {

//如果文件自身携带编码规则,那就使用自带的编码规则

inputSource.setEncoding(encodedResource.getEncoding());

}

//进入了加载Bean的核心部分

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

}

catch (IOException ex) {

throw new BeanDefinitionStoreException(

"IOException parsing XML document from " + encodedResource.getResource(), ex);

}

//最终都会执行的操作

finally {

//当文件加载完后,无论失败与否,都要清楚在currentResources的存在

currentResources.remove(encodedResource);

//如果currentResources为空了,证明没有配置文件加载了

//当前线程的ThreadLocal直接清空这个集合

if (currentResources.isEmpty()) {

this.resourcesCurrentlyBeingLoaded.remove();

}

}

}

从源码上可以看到,这个重载的loadBeanDefinitions方法有以下功能

  • 判断文件是否为空

  • 使用了ThreadLocal检测、防止配置文件循环加载

  • Spring的自定义资源加载策略,其实就是给InputResource又套多了一层,最后的加载文件还是依赖于InputResource

  • 加载Bean的核心部分在doLoadBeanDefinitions方法

doLoadBeanDefinitions方法

这个方法就是加载Bean的核心了

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)

throws BeanDefinitionStoreException {

try {

//doLoadDocument方法就是加载XML文件并得到对应的Document

Document doc = doLoadDocument(inputSource, resource);

//根据返回的Dom去注册bean信息

总结

至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:

  1. 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
  2. 项目经历:只写明星项目,描述遵循 STAR 法则;
  3. 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;

以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

rce);

//根据返回的Dom去注册bean信息

总结

至此,文章终于到了尾声。总结一下,我们谈论了简历制作过程中需要注意的以下三个部分,并分别给出了一些建议:

  1. 技术能力:先写岗位所需能力,再写加分能力,不要写无关能力;
  2. 项目经历:只写明星项目,描述遵循 STAR 法则;
  3. 简历印象:简历遵循三大原则:清晰,简短,必要,要有的放矢,不要海投;

以及最后为大家准备的福利时间:简历模板+Java面试题+热门技术系列教程视频

[外链图片转存中…(img-meX4Bhsg-1721068975896)]

[外链图片转存中…(img-uHNGSHC3-1721068975897)]

[外链图片转存中…(img-MTqVVzgv-1721068975897)]

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值