SpringBoot默认是将Tomcat作为嵌入式的servlet容器。

问题:

  1. 如何修改嵌入式的servlet容器?

    1)在配置文件中设置对应的属性值

    1. server.port=8081
    2. # Tomcat access日志的编码格式
    3. server.tomcat.accesslog.encoding=UTF-8
    4. # 最小的空闲线程个数
    5. server.tomcat.min-spare-threads=11
  1. 在spring1.x版本时,编写一个配置类,将EmbeddedServletContainerCustomizer加入到容器中,EmbeddedServletContainerCustomizer接口中的customize方法可以修改servlet的配置。
  1. @Bean //一定要将这个定制器加入到容器中
  2. public EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer(){
  3. return new EmbeddedServletContainerCustomizer() {
  4. //定制嵌入式的Servlet容器相关的规则
  5. @Override
  6. public void customize(ConfigurableEmbeddedServletContainer container) {
  7. container.setPort(8083);
  8. }
  9. };
  10. }

到了springboot2.x,上面那个EmbeddedServletContainerCustomizer已经被WebServerFactoryCustomizer取代,

  1. package org.springframework.boot.web.server;
  2. @FunctionalInterface
  3. public interface WebServerFactoryCustomizer<T extends WebServerFactory> {
  4. void customize(T factory);
  5. }

所以编写一个config实现这个接口,T是ConfigurableServletWebServerFactory

  1. @Component
  2. public class EmbeddedTomcatConfig implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
  3. @Override
  4. public void customize(ConfigurableServletWebServerFactory factory) {
  5. ((TomcatServletWebServerFactory)factory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
  6. @Override
  7. public void customize(Connector connector) {
  8. Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
  9. protocol.setMaxConnections(200);
  10. protocol.setMaxThreads(200);
  11. protocol.setSelectorTimeout(3000);
  12. protocol.setSessionTimeout(3000);
  13. protocol.setConnectionTimeout(3000);
  14. }
  15. });
  16. }
  17. }
  1. springboot能不能支持其他的servlet容器?

    支持Jetty,Undertow服务器。
    这里了解一下两者的一些特点,undertow是一款红帽旗下的开源容器,是轻量级的,它是一个 内嵌Web 服务器, 由两个核心 Jar 包组成,它支持IO/NIO,在多款同类产品的压测中,在高并发情况下表现出色, 它还提供了对 Servlet4.0 的支持,WebSocket的支持。用以满足 Web 应用巨大数量的客户端。jetty也是轻量级别的服务器,它更加灵活,可扩展性强,作为嵌入式服务器在自动测试环境下不需要外部环境的支持,且运行速度较快。

    首先去除Tomcat相关依赖,然后引入undertow的依赖,pom.xml依赖的变化

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. <exclusions>
  5. <!--去除Tomcat的依赖-->
  6. <exclusion>
  7. <artifactId>spring-boot-starter-tomcat</artifactId>
  8. <groupId>org.springframework.boot</groupId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>
  12. <!--引入undertow服务器的依赖-->
  13. <dependency>
  14. <artifactId>spring-boot-starter-undertow</artifactId>
  15. <groupId>org.springframework.boot</groupId>
  16. </dependency>

同样替换成jetty也是一样

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. <exclusions>
  5. <!--去除Tomcat的依赖-->
  6. <exclusion>
  7. <artifactId>spring-boot-starter-tomcat</artifactId>
  8. <groupId>org.springframework.boot</groupId>
  9. </exclusion>
  10. </exclusions>
  11. </dependency>
  12. <!--引入jetty服务器的依赖-->
  13. <dependency>
  14. <groupId>org.springframework.boot</groupId>
  15. <artifactId>spring-boot-starter-jetty</artifactId>
  16. </dependency>

使用外置的servlet容器

嵌入式tomcat容器的优缺点:

优点:简单,便携

缺点:默认不支持JSP、优化定制比较复杂(使用定制器【ServerProperties、自定义EmbeddedServletContainerCustomizer】,自己编写嵌入式Servlet容器的创建工厂【EmbeddedServletContainerFactory】);

外置的Servlet容器:外面安装的Tomcat—应用打成war包

步骤

  1. 必须创建一个war的项目,

  2. 将嵌入式的Tomcat制定成provided;

    1. <dependency>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-tomcat</artifactId>
    4. <scope>provided</scope>
    5. </dependency>
    1. 编写一个SpringBootServletInitializer的子类,这件事idea在我们创建好项目的时候就已经帮我们做好了。

      1. public class ServletInitializer extends SpringBootServletInitializer {
      2. @Override
      3. protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
      4. return application.sources(Springboot04JspApplication.class);
      5. }
      6. }
  3. 启动服务器就可以使用(注意这时候就不要再使用SpringBoot默认的主类的main方法启动服务器了,这样做是启动不了的)

原理

jar包:执行SpringBoot主类的main方法。启动IOC容器,创建嵌入式的servlet容器;

war包:启动服务器,服务器启动SpringBoot应用ServletInitializer】这个也就是idea创建的时候帮我们生成的类是SpringBootServletInitializer的子类。再启动IOC容器

规则:

1)服务器启动会创建当前web应用里面每一个jar包的ServletContainerInitializer实例;

2)、ServletContainerInitializer的实现会放在jar包的META-INF/services文件夹下,有一个名为

javax.servlet.ServletContainerInitializer的文件,内容就是ServletContainerInitializer的实现类的全类名

3)、还可以使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类;

流程:首先启动Tomcat,这时org\springframework\spring-web\5.2.3.RELEASE\spring-web-5.2.3.RELEASE.jar!\META-INF\services\javax.servlet.ServletContainerInitializer路径下的ServletContainerInitializer类就会起作用,打开这个类,查看他的实现,发现他上面@HandlesTypes({WebApplicationInitializer.class}),也就是说WebApplicationInitializer这个接口同样也创建出了实例对象。

打开继承树,发现他就是idea帮我们自动创建的那个类的父类所实现的接口,并且创建完WebApplicationInitializer后有调用了他们的onStartup方法.

  1. while(var4.hasNext()) {
  2. WebApplicationInitializer initializer = (WebApplicationInitializer)var4.next();
  3. initializer.onStartup(servletContext);
  4. }

但是我们的idea帮我们生成的ServletInitializer类并没有这个onStartup方法,所以看他的父类SpringBootServletInitializer,果然,SpringBootServletInitializer实现了WebApplicationInitializer接口,重写了onStartup方法。

  1. public void onStartup(ServletContext servletContext) throws ServletException {
  2. this.logger = LogFactory.getLog(this.getClass());
  3. //下面这个创建了IOC容器,点进去查看其实,方法就在本类中实现
  4. WebApplicationContext rootAppContext = this.createRootApplicationContext(servletContext);
  5. if (rootAppContext != null) {
  6. servletContext.addListener(new ContextLoaderListener(rootAppContext) {
  7. public void contextInitialized(ServletContextEvent event) {
  8. }
  9. });
  10. } else {
  11. this.logger.debug("No ContextLoaderListener registered, as createRootApplicationContext() did not return an application context");
  12. }
  13. }

createRootApplicationContext方法;

  1. protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
  2. SpringApplicationBuilder builder = this.createSpringApplicationBuilder();
  3. builder.main(this.getClass());
  4. ApplicationContext parent = this.getExistingRootWebApplicationContext(servletContext);
  5. if (parent != null) {
  6. this.logger.info("Root context already created (using as parent).");
  7. servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (Object)null);
  8. builder.initializers(new ApplicationContextInitializer[]{new ParentContextApplicationContextInitializer(parent)});
  9. }
  10. builder.initializers(new ApplicationContextInitializer[]{new ServletContextApplicationContextInitializer(servletContext)});
  11. builder.contextClass(AnnotationConfigServletWebServerApplicationContext.class);
  12. //调用config方法,子类重写了这个方法,将SpringBoot主程序类传了进来
  13. builder = this.configure(builder);
  14. builder.listeners(new ApplicationListener[]{new SpringBootServletInitializer.WebEnvironmentPropertySourceInitializer(servletContext)});
  15. //创建spring应用
  16. SpringApplication application = builder.build();
  17. if (application.getAllSources().isEmpty() && MergedAnnotations.from(this.getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) {
  18. application.addPrimarySources(Collections.singleton(this.getClass()));
  19. }
  20. Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the configure method or add an @Configuration annotation");
  21. if (this.registerErrorPageFilter) {
  22. application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
  23. }
  24. //启动spring
  25. return this.run(application);
  26. }

run方法的定义在SpringApplication类中找到

  1. public ConfigurableApplicationContext run(String... args) {
  2. StopWatch stopWatch = new StopWatch();
  3. stopWatch.start();
  4. ConfigurableApplicationContext context = null;
  5. Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
  6. this.configureHeadlessProperty();
  7. SpringApplicationRunListeners listeners = this.getRunListeners(args);
  8. listeners.starting();
  9. Collection exceptionReporters;
  10. try {
  11. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  12. ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
  13. this.configureIgnoreBeanInfo(environment);
  14. Banner printedBanner = this.printBanner(environment);
  15. context = this.createApplicationContext();
  16. exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
  17. this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  18. this.refreshContext(context);
  19. this.afterRefresh(context, applicationArguments);
  20. stopWatch.stop();
  21. if (this.logStartupInfo) {
  22. (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
  23. }
  24. listeners.started(context);
  25. this.callRunners(context, applicationArguments);
  26. } catch (Throwable var10) {
  27. this.handleRunFailure(context, var10, exceptionReporters, listeners);
  28. throw new IllegalStateException(var10);
  29. }
  30. try {
  31. listeners.running(context);
  32. return context;
  33. } catch (Throwable var9) {
  34. this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
  35. throw new IllegalStateException(var9);
  36. }
  37. }

SpringBoot嵌入式Servlet容器的更多相关文章

  1. java框架之SpringBoot(8)-嵌入式Servlet容器

    前言 SpringBoot 默认使用的嵌入式 Servlet 容器为 Tomcat,通过依赖关系就可以看到: 问题: 如何定制和修改 Servlet 容器相关配置? SpringBoot 能否支持其它 ...

  2. springboot(八) 嵌入式Servlet容器自动配置原理和容器启动原理

    1.嵌入式Servlet容器自动配置原理 1.1 在spring-boot-autoconfigure-1.5.9.RELEASE.jar => springboot自动配置依赖 jar包下,E ...

  3. SpringBoot源码学习系列之嵌入式Servlet容器

    目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ...

  4. SpringBoot(七) -- 嵌入式Servlet容器

    一.嵌入式Servlet容器 在传统的开发中,我们在完成开发后需要将项目打成war包,在外部配置好TomCat容器,而这个TomCat就是Servlet容器.在使用SpringBoot开发时,我们无需 ...

  5. SpringBoot配置嵌入式Servlet容器

    1).如何定制和修改Servlet容器的相关配置: 1.修改和server有关的配置(ServerProperties[也是EmbeddedServletContainerCustomizer]): ...

  6. 嵌入式Servlet容器自动配置和启动原理

    EmbeddedServletContainerAutoConfiguration:嵌入式的Servlet容器自动配置? @AutoConfigureOrder(Ordered.HIGHEST_PRE ...

  7. 配置嵌入式Servlet容器

    SpringBoot默认是用的是Tomcat作为嵌入式的Servlet容器:问题?1).如何定制和修改Servlet容器的相关配置:1.修改和server有关的配置(ServerProperties) ...

  8. 19、配置嵌入式servlet容器(下)

    使用外置的Servlet   嵌入式Servlet容器:应用打成可执行的j ar 优点:简单.便携: 缺点:默认不支持JSP.优化定制比较复杂         使用定制器[ServerProperti ...

  9. 18、配置嵌入式servlet容器(2)

    使用其他Servlet容器 -Jetty(长连接) -Undertow(不支持jsp) 替换为其他嵌入式Servlet容器   默认支持: Tomcat(默认使用) Jetty: <depend ...

随机推荐

  1. 刚开始学习Javascript的一些基础小知识,从入门到崩溃,希望对大家有帮助(只适合初学者)

    一.简介 1.JavaScript一种直译式脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型,js不能操作文件. 重要的开始啦!!!!! 引入javascript: 行间js <d ...

  2. Mysql为什么使用b+树,而不是b树、AVL树或红黑树?

    首先,我们应该考虑一个问题,数据库在磁盘中是怎样存储的?(答案写在下一篇文章中) b树.b+树.AVL树.红黑树的区别很大.虽然都可以提高搜索性能,但是作用方式不同. 通常文件和数据库都存储在磁盘,如 ...

  3. rsync 参数说明及使用参数笔记

    第1章 rsync 命令简介 rsync 是一款开源的.快速的.多功能的.可实现全量及增量的本地或远程数据镜像同步备份的优秀工具. 1.1.1 语法格式 三种模式: 1)本地模式 rsync [选项] ...

  4. STL—— 容器(vector)的内存分配,声明时的普通构造&带参构造

    vector 的几种带参构造 & 初始化与内存分配: 1. 普通的带参构造: vector 的相关对象可以在声明时通过 vector 的带参构造函数进行内存分配,如下: 1 #include ...

  5. vscode 编辑python文件

    1 安装python 自动姿势 Chinese # 换成中文 path Autocomplete 路径自动补全 Vetur vue文件补全 配置文件 首选项-设置 应用程序 在 seyying.jso ...

  6. Spring Session解决Session共享

    1. 分布式Session共享   在分布式集群部署环境下,使用Session存储用户信息,往往出现Session不能共享问题.   例如:服务集群部署后,分为服务A和服务B,当用户登录时负载到服务A ...

  7. kafka监控之topic的lag情况监控

    需求描述:lag(滞后)是kafka消费队列性能监控的重要指标,lag的值越大,表示kafka的堆积越严重.本篇文章将使用python脚本+influxdb+grafana的方式对kafka的offs ...

  8. JDK下载与安装

    Java有很多个版本,最新的版本会兼容之前的. 先附上下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downlo ...

  9. 详解汇编语言B和LDR指令与相对跳转和绝对跳转的关系

    @ 目录 为什么要有相对跳转和绝对跳转? 在程序中只有相对跳转/绝对跳转是否可以? B(BL)和LDR指令具体怎么执行的? B(BL)和LDR跳转范围是如何规定的? 为什么要有相对跳转和绝对跳转? 顺 ...

  10. 【Idea插件】kotlin的orm框架一键生成代码框架

    @font-face { font-family: octicons-link; src: url("data:font/woff;charset=utf-8;base64,d09GRgAB ...