SpringBoot 嵌入式web容器的启动原理详解
作者:AnalogElectronic 发布时间:2021-12-29 23:23:14
SpringBoot应用启动run方法
SpringApplication.java 中执行的代码
@SpringBootApplication
@EnableAsync //使用异步注解@Async 需要在这里加上@EnableAsync
@MapperScan("springboot.dao") //不可或缺作用是扫描dao包下面的所有mapper装配
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class,args);
}
}
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
return run(new Class[]{primarySource}, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
return (new SpringApplication(primarySources)).run(args);
}
private void refreshContext(ConfigurableApplicationContext context) {
this.refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext)applicationContext).refresh();
}
ServletWebServerApplicationContext.java执行的方法
public final void refresh() throws BeansException, IllegalStateException {
try {
super.refresh();
} catch (RuntimeException var2) {
this.stopAndReleaseWebServer();
throw var2;
}
}
protected void onRefresh() {
super.onRefresh();
try {
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = this.getWebServerFactory();
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var4) {
throw new ApplicationContextException("Cannot initialize servlet context", var4);
}
}
this.initPropertySources();
}
protected ServletWebServerFactory getWebServerFactory() {
String[] beanNames = this.getBeanFactory().getBeanNamesForType(ServletWebServerFactory.class);
if (beanNames.length == 0) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean.");
} else if (beanNames.length > 1) {
throw new ApplicationContextException("Unable to start ServletWebServerApplicationContext due to multiple ServletWebServerFactory beans : " + StringUtils.arrayToCommaDelimitedString(beanNames));
} else {
return (ServletWebServerFactory)this.getBeanFactory().getBean(beanNames[0], ServletWebServerFactory.class);
}
}
//配置嵌入式的servlet容器
@Bean
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> MyCustomizer(){
return new WebServerFactoryCustomizer<ConfigurableWebServerFactory>() {
@Override
public void customize(ConfigurableWebServerFactory factory) {
factory.setPort(8081);
}
};
}
SpringBoot 2.x 版本
嵌入式Servlet容器自动配置原理以及启动原理
一、版本说明
Spring Boot 2.x 版本的嵌入式Servlet容器自动配置是通过 WebServerFactoryCustomizer定制器 来定制的,而在Spring Boot 1.x 版本中我们是通过 EmbeddedServletContainerCustomizer 嵌入式的Servlet容器定制器来定制的。由于之前看的资料都是1.x的版本,但是我使用的是2.x,所以在这里记录一下2.x版本的嵌入式Servlet容器自动配置原理以及启动原理。
二、总结
嵌入式Servlet容器自动配置原理以及启动原理有三大步:
步骤:
SpringBoot 根据导入的依赖信息,自动创建对应的 WebServerFactoryCustomizer(web服务工厂定制器);
WebServerFactoryCustomizerBeanPostProcessor(web服务工厂定制器组件的后置处理器)获取所有类型为web服务工厂定制器的组件(包含实现WebServerFactoryCustomizer接口,自定义的定制器组件),依次调用customize()定制接口,定制Servlet容器配置;
嵌入式的Servlet容器工厂创建tomcat容器,初始化并启动容器。
三、嵌入式Servlet容器自动配置原理(以Tomcat为例)
1、首先找到 EmbeddedWebServerFactoryCustomizerAutoConfiguration ,在里面我们可以看到SpringBoot支持的 servlet容器
//SprinBoot支持的servlet容器有三个Tomcat、Jetty、Undertow,但是默认配置的是Tomcat
//嵌入式的Undertow
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({Undertow.class, SslClientAuthMode.class})
public static class UndertowWebServerFactoryCustomizerConfiguration {
public UndertowWebServerFactoryCustomizerConfiguration() {
}
@Bean
public UndertowWebServerFactoryCustomizer undertowWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
return new UndertowWebServerFactoryCustomizer(environment, serverProperties);
}
}
//嵌入式的Jetty
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({Server.class, Loader.class, WebAppContext.class})
public static class JettyWebServerFactoryCustomizerConfiguration {
public JettyWebServerFactoryCustomizerConfiguration() {
}
@Bean
public JettyWebServerFactoryCustomizer jettyWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
return new JettyWebServerFactoryCustomizer(environment, serverProperties);
}
}
//嵌入式的Tomcat
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnClass({Tomcat.class, UpgradeProtocol.class})
public static class TomcatWebServerFactoryCustomizerConfiguration {
public TomcatWebServerFactoryCustomizerConfiguration() {
}
@Bean
public TomcatWebServerFactoryCustomizer tomcatWebServerFactoryCustomizer(Environment environment, ServerProperties serverProperties) {
return new TomcatWebServerFactoryCustomizer(environment, serverProperties);
}
}
2、准备环节
1)在以下位置打一个断点
2)、点进 TomcatWebServerFactoryCustomizer 也就是上图 return 的,然后在里面的如下位置打一个断点
3)、然后在里面debug程序,我们在控制台就可以看到如下信息
3、按照上图从下往上分析。我们启动springboot应用时,都是直接运行主程序的main方法,然后调用里面的run方法,如下图
4、调用完run方法,回来到 refreshContext 方法,这个方法是帮我们创建IOC容器对象,并且初始化容器,创建容器中的每一个组件
5、在调用了 reflesh 方法刷新刚才的IOC容器后,来到 onreflesh 方法,调用createWebServer()方法,创建WebServer
6、来到createWebServer()方法,该方法最终能够获取到一个与当前应用(也就是总结里说的第一步,根据我们导入的依赖来获取)所导入的Servlet类型相匹配的web服务工厂,通过工厂就可以获取到相应的 WebServerFactoryCustomizer (Web服务工厂定制器)
注:createWebServer()执行后,我们其实来到了 EmbeddedWebServerFactoryCustomizerAutoConfiguration,然后根据条件(配置的依赖)配置哪一个Web服务器
我们通过查看 ServletWebServerFactory 的子类,可以看到其中三个就是Tomcat、Jetty和Undertow,根据我们的配置,所以这里获取到的是 TomcatWebServerFactoryCustomizer
至此,TomcatWebServerFactoryCustomizer组件创建完成,对应的服务配置类也已添加到IOC容器。
7、因为容器中某个组件要创建对象就会惊动后置处理器 然后就到 WebServerFactoryCustomizerBeanPostProcessor(web服务工厂定制器组件的后置处理器),该类负责在bean组件初始化之前执行初始化工作。它先从IOC容器中获取所有类型为WebServerFactoryCustomizerBeans(web服务工厂定制器的组件)
通过后置处理器获取到的TomcatWebServerFactoryCustomizer调用customize()定制方法,获取到Servlet容器相关配置类ServerProperties,进行自动配置
至此,嵌入式Servlet容器的自动配置完成。
注:从源码分析可以得出配置嵌入式Servlet容器的两种解决方案:
1、在全局配置文件中,通过server.xxx来修改和server有关的配置:
server.port=8081
server.tomcat.xxx...
2、实现WebServerFactoryCustomizer接口,重写它的customize()方法,对容器进行定制配置:
@FunctionalInterface
public interface WebServerFactoryCustomizer<T extends WebServerFactory> {
void customize(T factory);
}
四、嵌入式Servlet容器启动原理(以Tomcat为例)
1、应用启动后,根据导入的依赖信息,创建了相应的Servlet容器工厂,创建了TomcatServletWebServerFactory,调用getWebServer()方法创建Tomcat容器:(其实就是重写了ServletWebServerFactory里面的getWebServer方法)
找到下面的getTomcatWebServer方法
2、然后点进去分析TomcatWebServer的有参构造器,执行 initialize() 方法
3、点进去就可以发现,里面通过调用start方法来启动Tomcat
来源:https://blog.csdn.net/AnalogElectronic/article/details/110953205


猜你喜欢
- 前言一般数据库的表结构都会有update_time,修改时间,因为这个字段基本与业务没有太大关联,因此开发过程中经常会忘记设置这两个字段的值
- 前言今天看到某一篇文章的一句话 单例DCL 前面加 V 。就这句话让我把 单例模式 又仔细看了一遍。Java
- 本文实例讲述了Android编程之DatePicker和TimePicke简单时间监听用法。分享给大家供大家参考,具体如下:DatePick
- 前言:如果让大家说出一款国内比较热门的社交软件,那无疑就是QQ和微信了,说到微信,无不例外的会想到微信公众号和小程序,所以现在它们已经是很多
- Purpose开发人员在合作的时候经常遇到以下场景:1.开发人员A在自己的本地数据库做了一些表结构的改动,并根据这些改动调整了DAO层的代码
- 悲观锁、乐观锁简介: 悲观锁:同步操作。即用户A在操作某条数据时,为其上锁,限制其他用户操作,用户A操作完成提交事务后其他用户方可
- CDMA猫真是!@#¥#%(*,连PDU都不支持,只能发文本短信。而且发中文短信居然是UNICODE,无法在超级终端里输入。只能写程序。 网
- 一、概述log4net库是Apache log4j框架在Microsoft .NET平台的实现,是一个帮助程序员将日志信息输出到各种目标(控
- 写在前面作为程序员,多多少少都会遇到一些内存溢出的场景,如果你还没遇到,说明你工作的年限可能比较短,或者你根本就是个假程序员!哈哈,开个玩笑
- 由于我使用的是properties类型的配置文件,在对druid的参数进行配置的时候,多加了druid,也就是spring.datasour
- 本文主要是分析Spring bean的循环依赖,以及Spring的解决方式。 通过这种解决方式,我们可以应用在我们实际开发项目中。1. 什么
- 通常,在这个页面中会用到很多控件,控件会用到很多的资源。Android系统本身有很多的资源,包括各种各样的字符串、图片、动画、样式和布局等等
- 1、单点登录三种常见的方式(1)Session广播机制(Session复制)(2)使用Cookie+Redis实现(3)使用token实现2
- 数据校验在web应用里是非常重要的功能,尤其是在表单输入中。在这里采用Hibernate-Vapdator进行校验,该方法实现了JSR-30
- 本文实例为大家分享了Android Scroller的使用方法,供大家参考,具体内容如下1、scrollTo和ScrollByView类定义
- 前言大家应该都知道,在Android中,我们对于View进行模拟点击事件,很容易,比如调用View.performClick即可。但是有些时
- 需要的jar包:数据库代码:create database school character set utf8;use school;CRE
- Java Hibernate对象
- 本文实例为大家分享了Android studio点击跳转WebView的具体代码,供大家参考,具体内容如下代码文件import androi
- 第9版《Java核心技术卷Ⅰ》的第607页介绍了一个方法:Collections类中的sort方法可以对实现了List接口的集合进行排序。这