Spring源码之六-onRefresh()方法
Spring源码之六-onRefresh()方法
大家好,我是程序员田同学。
今天带大家解读Spirng源码之六的onRefresh()方法,这是refresh()的其中的一个方法,看似是一个空方法,实则他是非常非常重要的,对于提高Spring的扩展性。
老规矩,先贴上Spring的核心方法refresh()方法的源码,以便读者可以丝滑入戏。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//1、刷新前的准备
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//2、将会初始化 BeanFactory、加载 Bean、注册 Bean
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//3、设置 BeanFactory 的类加载器,添加几个 BeanPostProcessor,手动注册几个特殊的 bean
prepareBeanFactory(beanFactory);
try {
//4、模板方法
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
//执行BeanFactory后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 5、Register bean processors that intercept bean creation.
//注册bean后置处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
//国际化
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//6、模板方法--springboot实现了这个方法
onRefresh();
// Check for listener beans and register them.
//7、注册监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//8、完成bean工厂的初始化**方法**********************************************
finishBeanFactoryInitialization(beanFactory);
//9、 Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
onRefresh()是模板方法,具体的子类可以在这里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
这是onRefresh()的主要作用,那么文章到这里就结束了,感谢阅读!
开玩笑,只说作用不举例那和耍流氓没有什么区别,接下来就以Spirng的典型实现Springboot来举例。
该方法的执行时机是Spring已经加载好了一些特殊的bean(内置的一些bean,实现了bean工厂后置处理器的类)之后,在实例化单例bean之前。让我们来看Springboot是怎么调用这个模板方法的。
一路的点击Springboot的核心入口run()方法,一路找到了我们今天的主角,Spring的refresh()方法中的onRefresh()方法。
点击查看Springboot的onRresh()的实现方法。
有两个包路径含有boot的,一定就是Spirngboot的实现方法。
这是Spirng的onRresh()的实现方法。
比对一下Spirng的onRresh()和SpirngbootRefersh的实现类对比,Springboot多了两个实现类,ReactiveWebServerApplicationContext类和ServletWebServerApplicationContext类。
我们分别查看这两个实现的onRresh()方法都做了什么?
方法名都是createWebServer()方法,以为这两个方法都是一个方法,仔细一看发现并不是。
两个createWebServer()方法做了什么呢?我们debug进去搂一眼。
ReactiveWebServerApplicationContext类的onRresh()方法并没有执行到,见名知意应该是跟webServer管理相关的,限于篇幅问题,留个坑暂时放在吧。
ServletWebServerApplicationContext类的onRefresh()方法执行到了,我们进去一探究竟。
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = getServletContext();
//第一次进来webServer servletContext都是null,会进到if分支里面
if (webServer == null && servletContext == null) {
//这里就会来查找ServletWebServerFactory,也就是web容器的工厂,具体看下getWebServerFactory()方法,
// 还是ServletWebServerApplicationContext这个类的方法
//创建了 TomcatServletWebServerFactory 类
ServletWebServerFactory factory = getWebServerFactory();
//创建 Tomcat
this.webServer = factory.getWebServer(getSelfInitializer());
}
else if (servletContext != null) {
try {
getSelfInitializer().onStartup(servletContext);
}
catch (ServletException ex) {
throw new ApplicationContextException("Cannot initialize servlet context", ex);
}
}
initPropertySources();
}
核心应该是 factory.getWebServer(getSelfInitializer()),这个方法是创建了一个容器。都有哪些容器呢?
我们看一下他的实现类有Jetty、Mock、Tomcat*,Tomcat就不必提了,Jetty略有耳闻和Tomcat并列的容易。
那mock是什么呢,带着求知的态度百度一下,没看懂,过!
我们还是重点看Tomcat。进去看TomcatServletWebServerFactory的实现类,new了一个Tomcat的对象,并做了一些Tomcat的设置,什么协议、端口......等等。
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
//创建 Tomcat
Tomcat tomcat = new Tomcat();
File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
// 同步非阻塞io协议
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
for (Connector additionalConnector : this.additionalTomcatConnectors) {
tomcat.getService().addConnector(additionalConnector);
}
prepareContext(tomcat.getHost(), initializers);
//这里会创建 TomcatWebServer 实例, 并返回
return getTomcatWebServer(tomcat);
}
好了,到此就把spirng的模板方法onRefresh()在Springboot中是怎么用的说说清楚了,顺道把Tomcat是怎么内嵌到Springboot中简要的讲解了一下。
貌似有点跑题了,讲onRefresh()方法呢,结果在springboot中饶了一大圈。不过,能让读者更好的理解Spirng和Springboot的关系,能认真的读读也是大有裨益的。
也是真的感叹Spirng作者们的功力之强,Spirng的扩展性有多少的强大。
Spring源码之六-onRefresh()方法的更多相关文章
- 【Spring源码分析】非懒加载的单例Bean初始化前后的一些操作
前言 之前两篇文章[Spring源码分析]非懒加载的单例Bean初始化过程(上篇)和[Spring源码分析]非懒加载的单例Bean初始化过程(下篇)比较详细地分析了非懒加载的单例Bean的初始化过程, ...
- Spring源码分析:非懒加载的单例Bean初始化前后的一些操作
之前两篇文章Spring源码分析:非懒加载的单例Bean初始化过程(上)和Spring源码分析:非懒加载的单例Bean初始化过程(下)比较详细地分析了非懒加载的单例Bean的初始化过程,整个流程始于A ...
- 我该如何学习spring源码以及解析bean定义的注册
如何学习spring源码 前言 本文属于spring源码解析的系列文章之一,文章主要是介绍如何学习spring的源码,希望能够最大限度的帮助到有需要的人.文章总体难度不大,但比较繁重,学习时一定要耐住 ...
- Spring 源码(5)BeanFactory使用的准备及自定义属性值解析器
BeanFactory 使用前的准备 上一篇文章 https://www.cnblogs.com/redwinter/p/16165878.html 介绍了自定义标签的使用,完成了AbstractAp ...
- Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean
Spring源码解析之八finishBeanFactoryInitialization方法即初始化单例bean 七千字长文深刻解读,Spirng中是如何初始化单例bean的,和面试中最常问的Sprin ...
- Spring源码 17 IOC refresh方法12
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码 14 IOC refresh方法9
参考源 https://www.bilibili.com/video/BV1tR4y1F75R?spm_id_from=333.337.search-card.all.click https://ww ...
- Spring源码情操陶冶-AbstractApplicationContext#onRefresh
承接前文Spring源码情操陶冶-AbstractApplicationContext#initApplicationEventMulticaster 约定web.xml配置的contextClass ...
- Spring源码之AbstractApplicationContext中refresh方法注释
https://blog.csdn.net/three_stand/article/details/80680004 refresh() prepareRefresh(beanFactory) 容器状 ...
随机推荐
- python网络爬虫-解析网页(六)
解析网页 主要使用到3种方法提取网页中的数据,分别是正则表达式.beautifulsoup和lxml. 使用正则表达式解析网页 正则表达式是对字符串操作的逻辑公式 .代替任意字符 . *匹配前0个或多 ...
- Flink源码学习笔记(2) 基于Yarn的自动伸缩容实现
1.背景介绍 随着实时计算技术在之家内部的逐步推广,Flink 任务数及计算量都在持续增长,集群规模的也在逐步增大,本着降本提效的理念,我们研发了 Flink 任务伸缩容功能: 提供自动伸缩容功能,可 ...
- Linux 总结
查看端口 lsof -i:8000 查看进程 ps -ef | grep python netstat -tunlp |grep 端口号 拷贝 cp 文件 生成文件名 做软连接找到目标文件目录 ...
- Redis学习笔记(二)redis 底层数据结构
在上一节提到的图中,我们知道,可以通过 redisObject 对象的 type 和 encoding 属性.可以决定Redis 主要的底层数据结构:SDS.QuickList.ZipList.Has ...
- Net6 DI源码分析Part2 Engine,ServiceProvider
ServiceProvider ServiceProvider是对IServiceProvider实现,它有一个internal的访问修饰符描述的构造,并需要两个参数IServiceCollectio ...
- docker简介及安装(1)
Docker简介 软件开发中最为麻烦的事情可能就是配置环境了.由于用户使用的操作系统具有多样性,即便使用跨平台的开发语言(如Java和Python)都不能保证代码能够在各种平台下都可以正常的运转,而且 ...
- UITabBarController管理原则
- iOS加载Gif图片的N种方式 By-H罗
1.系统UIImageView 多张图片组成动画 /** * UIImageView 动画 * Memory-23M */ -(void)gifPlay1 { // NSArray *array=@[ ...
- Shell脚本之编程规范和变量
Shell脚本编程规划和变量 1.Shell脚本概述 2.Shell编程规划 3.重定向与管道 4.Shell脚本变量 1.Shell脚本概述 Shell的作用:充当"翻译官"的角 ...
- 2021羊城杯比赛复现(Crypto)
bigrsa 题目: from Crypto.Util.number import * from flag import * n1 = 10383529640908175186077053551474 ...