1、前言简单介绍

SpringBoot的自动配置就是SpringBoot的精髓所在;对于SpringBoot项目是不需要配置Tomcat、jetty等等Servlet容器,直接启动application类既可,SpringBoot为什么能做到这么简捷?原因就是使用了内嵌的Servlet容器,默认是使用Tomcat的,具体原因是什么?为什么启动application就可以启动内嵌的Tomcat或者其它Servlet容器?ok,本文就已SpringBoot嵌入式Servlet的启动原理简单介绍一下

环境准备:

  • SmartGit
  • IntelliJ IDEA
  • Maven
  • SpringBoot2.2.1

本文先创建一个SpringBoot项目,基于最新的2.2.1版本,阅读源码之前先进行一些必要的应用代码实践,先学习应用实践,有助于理解源码

在SpringBoot官网找到嵌入式Servlet容器相关的描述:

Under the hood, Spring Boot uses a different type of ApplicationContext for embedded servlet container support. The ServletWebServerApplicationContext is a special type of WebApplicationContext that bootstraps itself by searching for a single ServletWebServerFactory bean. Usually a TomcatServletWebServerFactory, JettyServletWebServerFactory, or UndertowServletWebServerFactory has been auto-configured.

这是比较重要的信息,简单翻译一下,里面提到ServletWebServerApplicationContext这是一种特殊的ApplicationContext 类,也就是启动时候,用来扫描ServletWebServerFactory类型的类的,ServletWebServerFactory类是一个接口类,具体的实现类是TomcatServletWebServerFactory, JettyServletWebServerFactory, or UndertowServletWebServerFactory etc.

2、定制servlet容器

然后如何自定义嵌入式Servlet容器的配置?在官方文档里找到如图对应的描述:

方法1:修改application配置

从官方文档可以看出支持的配置有如下所示,所以要修改servlet容器配置,直接在application配置文件修改即可:

  • 网络设置: 监听端口(server.port)、服务器地址(server.address)等等
  • Session设置: 会话是否持久 (server.servlet.session.persistent),会话超时(server.servlet.session.timeout), 会话数据的位置 (server.servlet.session.store-dir), 会话对应的cookie配置 (server.servlet.session.cookie.*) 等等
  • 错误管理: 错误页面位置 (server.error.path)等等
  • SSL设置:具体参考Configure SSL
  • HTTP compression:具体参考Enable HTTP Response Compression

方法2:自定义WebServerFactoryCustomizer定制器类

从文档里还找到了通过新建自定义的WebServerFactoryCustomizer类来实现属性配置修改,WebServerFactoryCustomizer也就是一种定制器类:

import org.springframework.boot.web.server.WebServerFactoryCustomizer;import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;import org.springframework.stereotype.Component;/** * 
 * 自定义的WebServerFactory定制器类 * 

* @author nicky *

 * 修改记录 * 修改后版本: 修改人: 修改日期: 2019年12月01日 修改内容: * 

*/@Componentpublic class WebServerFactoryCustomizationBean implements WebServerFactoryCustomizer { @Override public void customize(ConfigurableServletWebServerFactory server) { server.setPort(8081); }}

ok,官方文档里提供了如上的代码实例,当然也可以通过@bean注解进行设置,代码实例如:

@Configurationpublic class MyServerConfig { /** * 自定义的WebServerFactory定制器类 * @return */ @Bean public WebServerFactoryCustomizer webServerFactoryCustomizer(){ return new WebServerFactoryCustomizer() { @Override public void customize(ConfigurableServletWebServerFactory factory) { factory.setPort(8082); } }; }}

3、变换servlet容器

SpringBoot2.2.1版本支持的内嵌servlet容器有tomcat、jetty(适用于长连接)、undertow(高并发性能不错,但是默认不支持jsp),不过项目默认使用的是Tomcat的

我们可以找新建的一个SpringBoot项目,要求是集成了spring-boot-starter-web的工程,在pom文件右键->Diagrams->Show Dependencies,可以看到对应的jar关系图:

ok,从图可以看出,SpringBoot默认使用是Servlet容器是Tomcat,然后如果要切换其它嵌入式Servlet容器,要怎么实现?我们可以在图示选择spring-boot-starter-tomcat右键exclusion,然后引入其它的servlet容器,pom配置如图:

org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-tomcat org.springframework.boot spring-boot-starter-jetty 

4、servlet容器启动原理

ok,有了前面应用方面的学习之后,就可以简单跟一下Springboot是怎么对servlet容器进行自动配置的?内嵌的默认Tomcat容器是怎么样启动的?

从之前博客的学习,可以知道Springboot的自动配置都是通过一些AutoConfiguration类进行自动配置的,所以同理本博客也找一些对应的类,ServletWebServerFactoryAutoConfiguration 就是嵌入式servlet容器的自动配置类,简单跟一下其源码

@Configuration(proxyBeanMethods = false)@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)@ConditionalOnClass(ServletRequest.class)@ConditionalOnWebApplication(type = Type.SERVLET)@EnableConfigurationProperties(ServerProperties.class)//使ServerProperties配置类起效@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class, ServletWebServerFactoryConfiguration.EmbeddedTomcat.class, ServletWebServerFactoryConfiguration.EmbeddedJetty.class, ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })//@Import是Spring框架的注解,作用是将对应组件加载到容器,这里关键的是BeanPostProcessorsRegistrar,一个后置处理类public class ServletWebServerFactoryAutoConfiguration { @Bean public ServletWebServerFactoryCustomizer servletWebServerFactoryCustomizer(ServerProperties serverProperties) { return new ServletWebServerFactoryCustomizer(serverProperties); }//Tomcat的定制器类,起作用的条件是有Tomcat对应jar有引入项目的情况,默认是引入的,所以会执行Tomcat的servletWeb工厂定制类 @Bean @ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat") public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer( ServerProperties serverProperties) { return new TomcatServletWebServerFactoryCustomizer(serverProperties); } .... //注册重要的后置处理器类WebServerFactoryCustomizerBeanPostProcessor,在ioc容器启动的时候会调用后置处理器 public static class BeanPostProcessorsRegistrar implements ImportBeanDefinitionRegistrar, BeanFactoryAware { private ConfigurableListableBeanFactory beanFactory; //设置ConfigurableListableBeanFactory @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { if (beanFactory instanceof ConfigurableListableBeanFactory) { this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; } } @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if (this.beanFactory == null) { return; } registerSyntheticBeanIfMissing(registry, "webServerFactoryCustomizerBeanPostProcessor", WebServerFactoryCustomizerBeanPostProcessor.class); registerSyntheticBeanIfMissing(registry, "errorPageRegistrarBeanPostProcessor", ErrorPageRegistrarBeanPostProcessor.class); } private void registerSyntheticBeanIfMissing(BeanDefinitionRegistry registry, String name, Class> beanClass) { if (ObjectUtils.isEmpty(this.beanFactory.getBeanNamesForType(beanClass, true, false))) { RootBeanDefinition beanDefinition = new RootBeanDefinition(beanClass); beanDefinition.setSynthetic(true); registry.registerBeanDefinition(name, beanDefinition); } } }}

从自动配置类里,我们并不能很明确地理解自动配置是怎么运行的,只看重关键的一些信息点,比如注册了Tomcat的ServletWebServer工厂的定制器类,方法是tomcatServletWebServerFactoryCustomizer,还有一个后置处理类BeanPostProcessorsRegistrar,后置处理是Spring源码里是很关键的,所以这里可以继续点一下TomcatServletWebServerFactoryCustomizer,Tomcat的webServer工厂定制器类

也是一个WebServerFactoryCustomizer类型的类,从前面的应用学习,这个类是进行servlet容器的一些定制

这个是关键的方法,主要是拿ServerProperties配置类里的信息进行特定属性定制

所以,这里就可以知道Tomcat的配置是通过定制器类TomcatServletWebServerFactoryCustomizer进行定制的,其工厂类是TomcatServletWebServerFactory

TomcatServletWebServerFactory工厂类进行Tomcat对象的创建,必要参数的自动配置

ok,简单跟了一下源码之后,我们知道了TomcatServletWebServerFactoryCustomizer是Tomcat的定制器类,Tomcat对象的创建是通过TomcatServletWebServerFactory类的,然后,有个疑问,这个定制器类是什么时候创建的?为什么一启动Application类,嵌入式的Tomcat也启动了?打成jar格式的Springboot项目,只要运行jar命令,不需要启动任何servlet容器,项目也是正常运行的?然后这个BeanPostProcessorsRegistrar后置处理类有什么作用?ok,带着这些疑问,我们还是用调试一下源码

如图,打断点调试,看看Tomcat定制器是怎么创建的?

定制器类被调用了,其对应的工厂类也会起作用,打个断点,看看工厂类是怎么调用的?

ok,启动Application类,在idea里调试,如图,可以跟着调用顺序,一点点跟源码,如图所示,调用了Springboot的run方法

run方法里的刷新上下文方法,refreshContext其实也就是创建ioc容器,初始化ioc容器,并创建容器的每一个组件

这里注意到了,调用到了ServletWebServerApplicationContext类的refresh方法,ServletWebServerApplicationContext类前面也介绍到了,这个类是一种特殊的ApplicationContext类,也就是一些ioc的上下文类,作用于WebServer类型的类

创建webServer类,先创建ioc容器,调用基类的onRefresh方法,然后再调用createWebServer方法

ioc的servletContext组件没被创建的情况,调用ServletWebServerFactory类获取WebServer类,有servletContext的情况,直接从ioc容器获取

扫描ioc容器里是否有对应的ServletWebServerFactory类,TomcatServletWebServerFactory是其中一种,通过调试,是有扫描到的,所以从ioc容器里将这个bean对应的信息封装到ServletWebServerFactory对象

接着是ioc容器创建bean的过程,这个一个比较复杂的过程,因为是单例的,所以是调用singleObjects进行存储

bean被创建之后,调用了后置处理器,这个其实就是Spring的源码里的bean的创建过程,后置处理器是很关键的,在bean被创建,还没进行属性赋值时候,就调用了后置处理器

关键点,这里是检测是否有WebServerFactory工厂类,前面的调试发现已经有Tomcat的WebServer工厂类,所以是会调用后置处理器的

调用了WebServerFactoryCustomizerBeanPostProcessor这个后置处理类,然后拿到一个WebServerFactoryCustomizer定制器类,也就是TomcatWebServerFactoryCustomizer,通过后置处理器调用定制方法customize

然后WebServerFactoryCustomizerBeanPostProcessor这个后置处理器是什么注册的?往前翻Springboot的自动配置类,在这里找到了WebServerFactoryCustomizerBeanPostProcessor的注册

ok,继续调试源码,BeanWrapperImpl创建bean实例

ok,Tomcat定制器类被调用了,是通过后置处理器调用的

然后就是之前跟过的定制方法customize执行:

Tomcat的WebServer工厂类创建Tomcat对象实例,进行属性配置,引擎设置等等

端口有设置就创建TomcatwebServer对象

TomcatWebServer启动Tomcat,如图代码所示:

ok,跟了源码,您是否有一个疑问?Tomcat的工厂类TomcatServletWebServerFactory是什么时候创建的?好的,返回前面配置类看看,如图,这里用import引入了EmbeddedTomcat类

ok,EmbeddedTomcat是一个内部的配置类,条件是有引入Tomcat对应的jar,就会自动创建工厂类,很显然,Springboot默认是有引入的

ok,经过源码比较简单的学习,思路就很清晰了

Springboot的ServletWebServerFactoryAutoConfiguration是嵌入式Servlet容器的自动配置类,这个类的主要作用是创建TomcatServletWebServerFactory工厂类,创建定制器类TomcatServletWebServerFactoryCustomizer,创建FilterRegistrationBean类,同时很关键的一步是注册后置处理器webServerFactoryCustomizerBeanPostProcessor

然后Springboot的Application类一启动,就会执行run方法,run经过一系列调用会通过ServletWebServerApplicationContext的onRefresh方法创建ioc容器,然后通过createWebServer方法,createWebServer方法会去ioc容器里扫描是否有对应的ServletWebServerFactory工厂类(TomcatServletWebServerFactory是其中一种),扫描得到,就会触发webServerFactoryCustomizerBeanPostProcessor后置处理器类,这个处理器类会获取TomcatServletWebServerFactoryCustomizer定制器,并调用customize方法进行定制,这时候工厂类起作用,调用getWebServer方法进行Tomcat属性配置和引擎设置等等,再创建TomcatWebServer启动Tomcat容器

ok,本问只是简单跟一下嵌入式Tomcat容器的启动过程,可以看出Springboot的强大,还是基于Spring框架的,比如本博客提到的后置处理器,以及bean工程创建bean实例的过程,都是通过Spring框架实现的

servlet如何使用session把用户的手机号修改_SpringBoot源码学习系列之嵌入式Servlet容器...相关推荐

  1. Windows用户层技术工具与源码分享

    Windows用户层技术工具与源码分享 文章目录 Windows用户层技术工具与源码分享 一.注入与隐藏 1.窗口界面介绍 2.远程线程注入 3.APC注入 4.突破SESSION0隔离的远程注入 5 ...

  2. 蘑菇君深入源码学习Tomcat系列 (1) - Tomcat与Servlet的那些事

    瞎扯淡 最近很焦虑,每天过着咸鱼般的生活,感觉前途渺茫.再这么下去,整个人就真成咸鱼了.焦虑来源于日复一日工作中,自己变得越来越麻木,不会动脑思考.憋说举一反三了,脑子多转一下都感觉要耗尽全身气力. ...

  3. php 用户认证,PHP用户认证及管理完全源码

    PHP用户认证及管理完全源码 作者:佚名 来源:CNZZ 2008-1-4 -- begin auth.inc -- $id = "xxxCOM"; if(!isset($PHP_ ...

  4. java计算机毕业设计BS用户小票系统(附源码、数据库)

    java计算机毕业设计BS用户小票系统(附源码.数据库) 项目运行 环境配置: Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Eclispe( ...

  5. Django基于用户画像的电影推荐系统源码(项目源代码)

    一.项目介绍 公众号:yk 坤帝 获取全部源代码 本系统是以Django作为基础框架,采用MTV模式,数据库使用MongoDB.MySQL和Redis,以从豆瓣平台爬取的电影数据作为基础数据源,主要基 ...

  6. 2023最新OneTheme彩虹易支付用户模板美化主题模板源码/包括Admin端

    正文: 2023最新OneTheme彩虹易支付用户模板美化主题模板源码 oneTheme1.0彩虹易支付模板,一款简洁而又免费的模板,告别简陋的原始UI,感受新的视觉体验 此模板当前不一定能满足所有人 ...

  7. 装饰者模式源码解析(spring-session mybatis jdk servlet)

    那在JDK中体现最明显的,就是JAVA IO方面的一些类,那在JAVA IO中,我们为了增加缓存,我们使用BufferedReader,那现在我们来看一下,那因为增加缓存的功能,类有很多,子类也就需要 ...

  8. jsp模糊查询_[内附完整源码和文档] 基于JSP+Servlet校园二手交易平台

    摘 要 本系统采用JSP/servlet技术,是使用Java编程语言编写的一套校园网二手交易平台软件.系统采用的是最近几年流行的B/S开发模式,以互联网方式运行,服务器端只需要安装本系统,而客户端用户 ...

  9. 基于jsp和servlet的蛋糕店售卖网站商城系统javaweb点心铺源码mysql

    本项目为前几天收费帮学妹做的一个项目,Java EE JSP项目,在工作环境中基本使用不到,但是很多学校把这个当做编程入门的项目来做,故分享出本项目供初学者参考. 一.项目描述 蛋糕店售卖网站java ...

最新文章

  1. 收下这份来自GitHub的神器,一图搞定Matplotlib!
  2. 二叉树-二叉树的镜像(递归法)
  3. 英语与计算机的整合,浅谈计算机应用与英语教学的整合
  4. git常用命令之stash
  5. SAP WebIDE的本地安装方式
  6. 服务引用代理类_在代理类中引用动态代理
  7. 使用拦截器分析Java EE应用程序的性能下降/提高
  8. 怎么判断一个机器可以跑多少用户和并发_美逛微信云发单机器人申请方法及其问题解答汇总...
  9. 机器学习初探(手写数字识别)HOG图片
  10. 物联网部署的5个阶段
  11. zabbix常见配置集合
  12. ps制作html图标素材,PS按钮图标制作
  13. 数据库学习资料和视频
  14. Altium Designer之多图纸设计
  15. 适用于 iOS、Android 和 Windows 设备的移动设备管理
  16. 清明节前后 市场爆发了
  17. 3D打印机硬件驱动-马林固件最新版本2.0.X中文注释(1)marlin 2.0.9.2 截至发稿时间2021年12月16日
  18. Android的MotionEvent和事件处理
  19. android通讯录实例(一)
  20. 网页批量更新快照软件-百度快照更新优化

热门文章

  1. 51Nod - 1183 编辑距离
  2. linux系统命令:yum和apt-get
  3. 页面的缓存与不缓存设置
  4. 计算机网络学习笔记-1.1.4-时延、 时延带宽积、RTT和利用率
  5. 【计算机网络复习】1.2.4 TCP/IP参考模型和5层参考模型
  6. LeetCode 670 最大交换 (暴力+贪心、Python)
  7. 牛客21805 字符串编码与解码
  8. AdaBoost 算法 入门
  9. 7-1 是否同一棵二叉搜索树 (30分)
  10. python中的变量的作用_Python中的变量作用域