1、源码解析

  prepareRefresh()容器刷新refresh()的第一个方法,是容器刷新前的准备工作。
 1 // 容器启动的开始时间  毫秒级
2 private long startupDate;
3 // 容器目前是否活跃的标记
4 private final AtomicBoolean active = new AtomicBoolean();
5 // 当前容器是否已经被关闭的标记
6 private final AtomicBoolean closed = new AtomicBoolean();
7 // 容器刷新前注册进来的监听器集合
8 private Set<ApplicationListener<?>> earlyApplicationListeners;
9 // 容器的监听器集合
10 private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
11 // 要发布的应用程序事件集合(在多播器未设置之前要发布的事件)
12 private Set<ApplicationEvent> earlyApplicationEvents;
13
14 // 刷新容器前的准备工作
15 protected void prepareRefresh() {
16 // Switch to active.
17 // 记录容器启动时间
18 this.startupDate = System.currentTimeMillis();
19 // 设置关闭状态为false
20 this.closed.set(false);
21 // 设置活跃状态为true
22 this.active.set(true);
23
24 // 日志记录
25 if (logger.isDebugEnabled()) {
26 if (logger.isTraceEnabled()) {
27 logger.trace("Refreshing " + this);
28 }
29 else {
30 logger.debug("Refreshing " + getDisplayName());
31 }
32 }
33
34 // 具体实现由子类完成,初始化属性资源
35 initPropertySources();
36
37 // 获取Environment对象,并验证当前系统需要的属性值是否都加载到了Environment对象中
38 getEnvironment().validateRequiredProperties();
39
40 // 准备监听器和事件的集合对象,默认为空的集合
41 if (this.earlyApplicationListeners == null) {
42 this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
43 }
44 else {
45 // 重置本地应用监听器为预刷新状态,清空集合缓存
46 this.applicationListeners.clear();
47 // 将容器刷新前的监听器与事件集合对象设置到当前容器监听器集合中
48 this.applicationListeners.addAll(this.earlyApplicationListeners);
49 }
50
51 // 创建刷新前的事件集合,依赖于多播器,一旦多播器是可用的,事件集合中的事件就可以被发布
52 this.earlyApplicationEvents = new LinkedHashSet<>();
53 }

综上可见,容器刷新前的准备工作prepareRefresh()完成以下事情:

  1、记录容器启动时间

  2、设置当前容器关闭状态为false
  3、设置当前容器活跃状态为true
  4、设置拓展点,初始化资源占位符
  5、设置环境Environment对象,并将当前系统属性值加载至环境对象中
  6、监听器、事件集合的处理 - Spring框架提供的扩展点,在SpringBoot中有应用。

2、应用

  Spring在prepareRefresh()有对初始化资源占位符initPropertySources()的拓展点,下面我们来看看如何实现拓展。
  initPropertySources()方法是AbstractApplicationContext中的待子类实现的方法。
protected void initPropertySources() {
// For subclasses: do nothing by default.
}

  从IOC源码(一):IOC容器启动流程核心方法概览中ClassPatchXmlApplicationContext类图中我们得知,ClassPatchXmlApplicationContext是AbstractApplicationContext的子类,下面我们来看看初始化资源占位符的具体实现。

2.1、定义配置文件 - snailsInitPropertySource.xml

1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="http://www.springframework.org/schema/beans"
3 xmlns:context="http://www.springframework.org/schema/context"
4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
6 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
7
8 </beans>

2.2、拓展初始化属性资源,重写initPropertySources()方法

 1 import org.springframework.beans.BeansException;
2 import org.springframework.context.support.ClassPathXmlApplicationContext;
3
4 // 初始化属性资源的拓展实现
5 public class SnailsInitApplicationContext extends ClassPathXmlApplicationContext {
6
7 public SnailsInitApplicationContext(String... configLocations) throws BeansException {
8 super(configLocations);
9 }
10
11 @Override
12 protected void initPropertySources() {
13 System.out.println("expand initPropertySource... ");
14 // 添加属性到Environment环境中
15 getEnvironment().getSystemProperties().put("address","中国");
16 // Environment环境中的必输属性,会通过validateRequiredProperties方法做校验
17 getEnvironment().setRequiredProperties("addr");
18 }
19 }

2.3、测试代码

 1 /**
2 * @Description: 测试拓展初始化资源属性拓展
3 * @author: snails
4 * @since: 2022/3/1 11:02
5 */
6 public class TestSnailsInitApplicationContext {
7 public static void main(String[] args) {
8 SnailsInitApplicationContext context = new SnailsInitApplicationContext("snailsInitPropertySource.xml");
9 }
10 }

2.4、执行结果

  getEnvironment().getSystemProperties().put("address","中国");
  address属性已经加载到environment#propertySources#propertySourceList集合中name为systemProperties的 source集合中,source中存储的是Properties对象。
  getEnvironment().setRequiredProperties("addr");
Exception in thread "main" org.springframework.core.env.MissingRequiredPropertiesException: The following properties were declared as required but could not be resolved: [addr]
at org.springframework.core.env.AbstractPropertyResolver.validateRequiredProperties(AbstractPropertyResolver.java:145)
at org.springframework.core.env.AbstractEnvironment.validateRequiredProperties(AbstractEnvironment.java:519)
at org.springframework.context.support.AbstractApplicationContext.prepareRefresh(AbstractApplicationContext.java:646)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:153)
at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:97)
at selfInitPropertySources.SnailsInitApplicationContext.<init>(SnailsInitApplicationContext.java:14)
at selfInitPropertySources.TestSnailsInitApplicationContext.main(TestSnailsInitApplicationContext.java:11)

校验失败,抛异常,校验流程分析如下

  1、将要校验的属性addr加入校验集合requiredProperties中;
  2、AbstractPropertyResolver#validateRequiredProperties()校验,遍历校验集合requiredProperties,通过key=addr从environment中的source集合中获取value;
  3、若通过key获取的value为空,抛出异常。

Spring IOC源码(二):IOC容器之 刷新前的准备的更多相关文章

  1. Spring Ioc源码分析系列--容器实例化Bean的四种方法

    Spring Ioc源码分析系列--实例化Bean的几种方法 前言 前面的文章Spring Ioc源码分析系列--Bean实例化过程(二)在讲解到bean真正通过那些方式实例化出来的时候,并没有继续分 ...

  2. 精尽Spring MVC源码分析 - WebApplicationContext 容器的初始化

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  3. Spring MVC源码(二) ----- DispatcherServlet 请求处理流程 面试必问

    前端控制器 前端控制器,即所谓的Front Controller,体现的是设计模式中的前端控制器模式.前端控制器处理所有从用户过来的请求.所有用户的请求都要通过前端控制器.SpringMVC框架和其他 ...

  4. SSH 之 Spring的源码(二)——Bean实例化

    首先来看一段代码,看过上一节的朋友肯定对这段代码并不陌生.这一段代码诠释了Spring加载bean的完整过程,包括读取配置文件,扫描包,加载类,实例化bean,注入bean属性依赖. <span ...

  5. 看看Spring的源码(二)——bean实例化

    首先来看一段代码,看过上一节的朋友肯定对这段代码并不陌生.这一段代码诠释了Spring加载bean的完整过程,包括读取配置文件,扫描包,加载类,实例化bean,注入bean属性依赖. public v ...

  6. 精尽Spring MVC源码分析 - 文章导读

    该系列文档是本人在学习 Spring MVC 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释 Spring MVC 源码分析 GitHub 地址 进行阅读 Spring 版本:5.2. ...

  7. Spring 源码剖析IOC容器(一)概览

    目录 一.容器概述 二.核心类源码解读 三.模拟容器获取Bean ======================= 一.容器概述 spring IOC控制反转,又称为DI依赖注入:大体是先初始化bean ...

  8. Spring Ioc源码分析系列--Bean实例化过程(二)

    Spring Ioc源码分析系列--Bean实例化过程(二) 前言 上篇文章Spring Ioc源码分析系列--Bean实例化过程(一)简单分析了getBean()方法,还记得分析了什么吗?不记得了才 ...

  9. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  10. Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析

    Spring Ioc源码分析系列--Ioc容器BeanFactoryPostProcessor后置处理器分析 前言 上一篇文章Spring Ioc源码分析系列--Ioc源码入口分析已经介绍到Ioc容器 ...

随机推荐

  1. Elasticsearch准实时索引实现(数据写入到es分片并存储到文件中的过程)

    溢写到文件系统缓存 当数据写入到ES分片时,会首先写入到内存中,然后通过内存的buffer生成一个segment,并刷到文件系统缓存中,数据可以被检索(注意不是直接刷到磁盘) ES中默认1秒,refr ...

  2. 修改-Python函数-2

    一.导入 $$f ( x , y ) = 2 x + 3 y$$ 上面括号里面的就是数学公式里的自变量,自变量就相当于函数里的参数. 二.为什么要有参数 如果一个大楼里有两种尺寸不一的窗户,显然在没有 ...

  3. 网络安全(一)主动进攻之DNS基础和ettercap实现DNS流量劫持

    alittlemc,个人原创,个人理解和观点.若有错误.不理解请与我联系,谢谢! 介绍了DNS的解析过程. DNS劫持的思路和实践. DNS 域名 以为live.bilibili.com为例子,从后到 ...

  4. Spring_Boot项目集成Swagger填坑

    事情是这样的: 最近疫情在家里闲的无聊 看了看Swagger-2 在练习的过程出现了错误 写个帖子 希望跟我有同样问题的朋友可以避雷. 下面进入正题: 编辑 我使用的swagger-2版本是2.9.4 ...

  5. vulnhub靶场之EMPIRE

    准备: 攻击机:虚拟机kali.本机win10. 靶机:EMPIRE: BREAKOUT,地址我这里设置的桥接,下载地址:https://download.vulnhub.com/empire/02- ...

  6. Java I/O(3):NIO中的Buffer

    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来- 之前在调用Channel的代码中,使用了一个名叫ByteBuffer类,它是Buffer的子类.这个叫Buffer的类是专门用来解决高速设备与低 ...

  7. Vue学习之--------组件嵌套以及VueComponent的讲解(代码实现)(2022/7/23)

    欢迎加入刚建立的社区:http://t.csdn.cn/Q52km 加入社区的好处: 1.专栏更加明确.便于学习 2.覆盖的知识点更多.便于发散学习 3.大家共同学习进步 3.不定时的发现金红包(不多 ...

  8. 一篇了解全MVCC

    一.什么是MVCC MVCC,全称Multi-Version Concurrency Control,即多版本并发控制,是一种并发控制的方法,一般用在数据库管理系统中,实现对数据库的并发访问,比如在M ...

  9. redux中间件

    Redux 中间件 什么是中间件? 中间件本质上就是一个函数,Redux允许我们通过中间件的方式,扩展和增强Redux应用程序,增强体现在对action处理能力上,之前的计数器与弹出框案例中.acti ...

  10. ES6 学习笔记(十一)迭代器和生成器函数

    1.前言 JavaScript提供了许多的方法来获取数组或者对象中的某个元素或者属性(迭代).从以前的for循环到之后的filter.map再到后来的for...in和for...of的迭代机制.只要 ...