看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead

代码过宽,可以shift + 鼠标滚轮 左右滑动查看

AbstractApplicationContext类中refresh()方法的第一个调用方法prepareRefresh()的跟踪。

@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing.
// 准备上下文的刷新
prepareRefresh();
···
}

直接进入。

prepareRefresh(零)

prepareRefresh方法在AbstractApplicationContext类中,此类是XmlWebApplicationContext的上层父类

// Prepare this context for refreshing.
// 准备 context 的刷新
prepareRefresh(); /**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*
* 准备 context 的刷新,设置他的启动数据、激活标志以及执行一些属性源的初始化
*/
protected void prepareRefresh() { // 启动时间
this.startupDate = System.currentTimeMillis(); // 此 context 是否已经被关闭
this.closed.set(false); // active 表示这个 context 当前是否处于活跃状态
this.active.set(true); if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
} // Initialize any placeholder property sources in the context environment // 1.在 context 的 environment 中初始化占位符属性源
initPropertySources(); // Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties // 验证所有被标记为必要的属性是否可解析,如果有遗失属性则不能解析并抛出异常,
// 可以参考setRequiredProperties方法
getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available... // 一旦有可利用的广播,允许早期的ApplicationEvents集合被发布
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}

1.initPropertySources

跟踪标记1的方法

initPropertySources 方法在 AbstractApplicationContext 中默认不做任何事情,具体业务流程由其子类覆盖完成,也就是在 AbstractRefreshableWebApplicationContext 类中进行,AbstractRefreshableWebApplicationContext 是XmlWebApplicationContext的父类

// Initialize any placeholder property sources in the context environment
// 1.在 context environment 中初始化占位符属性源
initPropertySources(); /**
* {@inheritDoc}
* <p>Replace {@code Servlet}-related property sources.
*
* 替换Servlet相关的属性源
*/
@Override
protected void initPropertySources() { // 在设置 root web application context 的 contextConfigLocation 属性时,已经调用过此方法。
// 在ContextLoader类中的configureAndRefreshWebApplicationContext方法中,
// 又调用了 initPropertySources 方法对 environment 进行了初始化
// 此时 environment 已存在,直接返回。
ConfigurableEnvironment env = getEnvironment();
if (env instanceof ConfigurableWebEnvironment) { // 1.1初始化属性源
((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig);
}
}

1.1 initPropertySources

跟踪标记1.1的方法

env(也就是environment对象)调用了initPropertySources方法,该方法的具体实现由ConfigurableWebEnvironment的子类StandardServletEnvironment进行。

environment对象是StandardServletEnvironment类的实例。

//1.1初始化属性源
((ConfigurableWebEnvironment) env).initPropertySources(this.servletContext, this.servletConfig); /**
* Replace any {@linkplain
* org.springframework.core.env.PropertySource.StubPropertySource stub property source}
* instances acting as placeholders with real servlet context/config property sources
* using the given parameters.
*
* 用真正的servlet context/config 属性源来替换作为占位符存在的 stub 属性源
*/
@Override
public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) { // 工具类来初始化属性源,进入这个方法
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
} /**
* Replace {@code Servlet}-based {@link StubPropertySource stub property sources} with
* actual instances populated with the given {@code servletContext} and
* {@code servletConfig} objects.
* <p>This method is idempotent with respect to the fact it may be called any number
* of times but will perform replacement of stub property sources with their
* corresponding actual property sources once and only once.
*
* 用<由servletContext和servletConfig对象填充的>实例去替换基于servlet的 stub 属性源。
* 这个方法幂等遵守这个情况:他可能被调用任意次数,但是有且仅会执行一次 stub 属性源与它所匹配
* 的实际属性源的替换
*/
public static void initServletPropertySources(
MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) { Assert.notNull(propertySources, "'propertySources' must not be null"); // 此条件第三项不通过。
// 在ContextLoader类的configureAndRefreshWebApplicationContext方法中
// 已调用过一次StandardServletEnvironment对象的initPropertySources方法,
// 完成了根属性源的替换,所以第三项不再通过
if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&
propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));
} //此处servletConfig为空,所以跳过
if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&
propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));
}
}

prepareRefresh方法只有这么多,接下来跟踪obtainFreshBeanFactory方法:

https://www.jianshu.com/p/144af98965d9

总结

  • 设置 context 关闭状态、激活标志等
  • 在 context 的 environment 中初始化占位符属性源,用真正的servlet context/config 属性源来替换作为占位符存在的 stub 属性源
  • 验证所有被标记为必要的属性是否可解析

prepareRefresh方法源码跟踪的更多相关文章

  1. prepareRefresh()方法源码探究

    该方法目的是做刷新上下文前的准备工作: 首先清空bean扫描器map中的内容,然后调用父类的prepareRefresh方法: 父类的准备刷新方法,主要做了3个工作: 1.简单的标志赋值----> ...

  2. loadBeanDefinitions方法源码跟踪(一)

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractBeanDe ...

  3. postProcessBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  4. prepareBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  5. loadBeanDefinitions方法源码跟踪(三)

    因为字数超过了限制,所以分成了三篇,承接上篇: https://www.jianshu.com/p/46e27afd7d96 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 4.parseCus ...

  6. obtainFreshBeanFactory方法源码跟踪

    看这篇文章之前可以先了解之前的跟踪流程,https://www.jianshu.com/p/4934233f0ead 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 AbstractApplic ...

  7. loadBeanDefinitions方法源码跟踪(二)

    因为字数超过了限制,所以分成了三篇,承接上篇: https://www.jianshu.com/p/a0cfaedf3fc5 代码过宽,可以shift + 鼠标滚轮 左右滑动查看 3.parseDef ...

  8. erlang下lists模块sort(排序)方法源码解析(一)

    排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ...

  9. Java源码跟踪阅读技巧

    转:https://www.jianshu.com/p/ab865109070c 本文基于Eclipse IDE 1.Quick Type Hierarchy 快速查看类继承体系. 快捷键:Ctrl ...

随机推荐

  1. 认识gets&read(buffer over flow is bof)

    gets不会检查输入的长度,从而有数据覆盖的风险,

  2. Python学习第十四课——面向对象基本思想part1

    面向对象的基本思想 # 写法1 person1 = { 'name': 'hanhan', ', 'sex': '男' } def xue_xi(person): print('%s在学习' % pe ...

  3. Linux (Ubuntu) 服务器安装MySQL,设置不限ip,root远程密码访问

    1.注释bind-address = 127.0.0.1 sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf   将bind-address = 127.0.0.1 ...

  4. 第2节 Scala中面向对象编程:12、13、14、15、16、trait

    6.4.  Scala中面向对象编程之trait 6.4.1.    将trait作为接口使用 Scala中的trait是一种特殊的概念: 首先先将trait作为接口使用,此时的trait就与Java ...

  5. mybatis利用generator自动生成的代码

    /** * 排序规则 */ protected String orderByClause; /** * 去重规则 */ protected boolean distinct; /** * where条 ...

  6. 时间戳转分秒 | 字符串的padStart()和padEnd()

    function _pad(num, n = 2) { let len = num.toString().length while (len < n) { num = '0' + num len ...

  7. C#二维数组的初始化和存取

    static void Main(string[] args) { ,]; ; j < ; j++) { strings[j, ] = $"{j}.0"; strings[j ...

  8. 使用Vue.js 和Chart.js制作绚丽多彩的图表

    前言 深入学习 chart.js 的选项来制作漂亮的图表.交互式图表可以给你的数据可视化提供很酷的展示方式.但是大多数开箱即用的解决方案用默认的选项并不能做出很绚丽的图表. 这篇文章中,我会教你如何自 ...

  9. 吴裕雄--天生自然python爬虫:使用requests模块的get和post方式抓取中国旅游网站和有道翻译网站翻译内容数据

    import requests url = 'http://www.cntour.cn/' strhtml = requests.get(url) print(strhtml.text) URL='h ...

  10. 如何:使用 as 和 is 运算符安全地进行强制转换(C# 编程指南)

    如何:使用 as 和 is 运算符安全地进行强制转换(C# 编程指南) 由于对象是多态的,因此基类类型的变量可以保存派生类型.若要访问派生类型的方法,需要将值强制转换回该派生类型.不过,在这些情况下, ...