1、概述

文章目录

  • 1、概述
  • 2、如何修改SpringBoot的默认配置
  • 3、定制和修改Servlet容器的相关配置
  • 4、注册Servlet三大组件
  • 5、替换为其他嵌入式Servlet容器
  • 6、嵌入式Servlet容器自动配置原理
  • 7、嵌入式Servlet容器启动原理

SpringBoot默认使用Tomcat作为嵌入式的Servlet容器

2、如何修改SpringBoot的默认配置

修改SpringBoot默认配置主要有以下三种模式:

(1)SpringBoot在自动配置很多组件的时候,先看容器中有没有用户自己配置的(@Bean、@Component)如果有就用用户配置的;如果没有,才自动配置;如果有些组件可以有多个(ViewResolver)将用户配置和自己默认的组合起来;

(2)在SpringBoot中会有非常多的xxxConfigurer帮助我们进行扩展配置

(3)在SpringBoot中会有很多的xxxCustomizer帮助我们进行定制配置

3、定制和修改Servlet容器的相关配置

(1)方法一:修改和Servlet相关的配置

通过ServerProperties也是EmbeddedServletContainerCustomizer

server.port=8081
server.context-path=/htzw
server.tomcat.uri-encoding=UTF-8//通用的Servlet容器设置
server.xxx
//Tomcat的设置
server.tomcat.xxx
//jetty的设置
server.jetty.xxx
//undertow的设置
server.undertow.xxx

(2)方法二:编写一个EmbeddedServletContainerCustomizer

EmbeddedServletContainerCustomizer嵌入式的Servlet容器的定制器,来修改Servlet容器的配置

@Configuration
public class MyServerConfig {//配置嵌入式的Servlet容器@Beanpublic EmbeddedServletContainerCustomizer embeddedServletContainerCustomizer() {return new EmbeddedServletContainerCustomizer() {//定制嵌入式的Servlet容器相关的规则@Overridepublic void customize(ConfigurableEmbeddedServletContainer container) {container.setPort(8899);container.setContextPath("/htzw");container.setSessionTimeout(36000, TimeUnit.SECONDS);}};}
}

4、注册Servlet三大组件

Servlet三大组件包括Servlet、Filter、Listener。

由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。
注册三大组件用以下方式

  • Servlet—ServletRegistrationBean

  • Filter—FilterRegistrationBean

  • Listener—ServletListenerRegistrationBean

(1)注册Servlet组件

首先,编写一个Servlet实现类

public class MyServlet extends HttpServlet {//处理get请求@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {resp.getWriter().write("Hello MyServlet …………");}
}

接着,通过ServletRegistrationBean注册自定义的Servlet,并设置具体的规则

@Configuration
public class MyServerConfig {//注册Servlet组件@Beanpublic ServletRegistrationBean myServlet() {ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet());registrationBean.setLoadOnStartup(1);registrationBean.setUrlMappings(Arrays.asList("/hello","/myServlet"));registrationBean.setName("myServletDemo");return registrationBean;}
}

(2)注册Filter组件

Filter组件的注册流程跟Servlet的流程一样。

首先,自定义Filter

public class MyFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {System.out.println("init…………");}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {System.out.println("MyFilter do………………");chain.doFilter(request,response);}@Overridepublic void destroy() {System.out.println("destroy…………");}
}

接着,通过FilterRegistrationBean注册自定义的Filter,并设置具体的规则

@Configuration
public class MyServerConfig {//注册Filter组件@Beanpublic FilterRegistrationBean myFilter() {FilterRegistrationBean registrationBean = new FilterRegistrationBean();registrationBean.setFilter(new MyFilter());registrationBean.setUrlPatterns(Arrays.asList("/hello", "/htzw"));return registrationBean;}
}

(3)注册Listener组件

首先,自定义Listener组件

public class MyListener implements ServletContextListener {@Overridepublic void contextInitialized(ServletContextEvent sce) {System.out.println("contextInitialized...web应用启动");}@Overridepublic void contextDestroyed(ServletContextEvent sce) {System.out.println("contextDestroyed...当前web项目销毁");}
}

接着,通过ServletListenerRegistrationBean注册自定义的Listener,并设置具体的规则

@Configuration
public class MyServerConfig {//注册Listener组件@Beanpublic ServletListenerRegistrationBean myListener() {ServletListenerRegistrationBean<MyListener> registrationBean = new ServletListenerRegistrationBean<>(new MyListener());return registrationBean;}
}

SpringBoot自动配置SpringMVC的时候,自动的注册SpringMVC的前端控制器:DispatcherServlet;DispatcherServletAutoConfiguration中:

@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)public ServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet) {ServletRegistrationBean registration = new ServletRegistrationBean(dispatcherServlet, this.serverProperties.getServletMapping());//默认拦截:/ 所有请求;包括静态资源,但不拦截jsp请求;/*会拦截jsp//可以通过server.servletPath来修改SpringMVC前端控制器默认拦截的请求路径registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);registration.setLoadOnStartup(this.webMvcProperties.getServlet().getLoadOnStartup());if (this.multipartConfig != null) {registration.setMultipartConfig(this.multipartConfig);}return registration;}

5、替换为其他嵌入式Servlet容器

SpringBoot能不能支持其他的Servlet容器呢?答案是能的,SpringBoot默认使用的是Tomcat,SpringBoot还支持Jetty、Undertow等Servlet容器。

其中,Jetty容器适用于长连接的应用场景;Undertow容器不支持JSP

默认支持:

Tomcat(默认使用此容器)

      <dependency>          <groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><!-- 引入web模块默认就是使用嵌入式的Tomcat作为Servlet容器 --></dependency>

Jetty容器

<!-- 引入web模块 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions></dependency><!--引入其他的Servlet容器--><dependency><artifactId>spring-boot-starter-jetty</artifactId><groupId>org.springframework.boot</groupId></dependency>

Undertow容器

<!-- 引入web模块 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><artifactId>spring-boot-starter-tomcat</artifactId><groupId>org.springframework.boot</groupId></exclusion></exclusions></dependency><!--引入其他的Servlet容器--><dependency><artifactId>spring-boot-starter-undertow</artifactId><groupId>org.springframework.boot</groupId></dependency>

6、嵌入式Servlet容器自动配置原理

EmbeddedServletContainerAutoConfiguration:嵌入式Servlet容器自动配置器

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@ConditionalOnWebApplication
@Import(BeanPostProcessorsRegistrar.class)
//导入BeanPostProcessorsRegistrar:Spring注解版;给容器中导入一些组件
//导入了EmbeddedServletContainerCustomizerBeanPostProcessor
//后置处理器:bean初始化前后(创建完对象,还没有赋值之前)执行初始化工作
public class EmbeddedServletContainerAutoConfiguration {@Configuration@ConditionalOnClass({ Servlet.class, Tomcat.class })//判断当前是否引入了Tomcat依赖@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)//判断当前容器没有用户自定义EmbeddedServletContainerFactory:嵌入式的Servlet容器工厂;作用:创建嵌入式的Servlet容器public static class EmbeddedTomcat {@Beanpublic TomcatEmbeddedServletContainerFactory tomcatEmbeddedServletContainerFactory() {return new TomcatEmbeddedServletContainerFactory();}}/*** Nested configuration if Jetty is being used.*/@Configuration@ConditionalOnClass({ Servlet.class, Server.class, Loader.class,WebAppContext.class })@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)public static class EmbeddedJetty {@Beanpublic JettyEmbeddedServletContainerFactory jettyEmbeddedServletContainerFactory() {return new JettyEmbeddedServletContainerFactory();}}/*** Nested configuration if Undertow is being used.*/@Configuration@ConditionalOnClass({ Servlet.class, Undertow.class, SslClientAuthMode.class })@ConditionalOnMissingBean(value = EmbeddedServletContainerFactory.class, search = SearchStrategy.CURRENT)public static class EmbeddedUndertow {@Beanpublic UndertowEmbeddedServletContainerFactory undertowEmbeddedServletContainerFactory() {return new UndertowEmbeddedServletContainerFactory();}}

(1)嵌入式Servlet容器工厂:EmbeddedServletContainerFactory

public interface EmbeddedServletContainerFactory {//获取嵌入式的Servlet容器EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers);}

通过Ctrl+H查看EmbeddedServletContainerFactory的依赖树

(2)嵌入式的Servlet容器:EmbeddedServletContainer

(3)以TomcatEmbeddedServletContainerFactory为例进行说明

@Overridepublic EmbeddedServletContainer getEmbeddedServletContainer(ServletContextInitializer... initializers) {//创建一个TomcatTomcat tomcat = new Tomcat();//配置Tomcat的基本环节File baseDir = (this.baseDirectory != null ? this.baseDirectory: createTempDir("tomcat"));tomcat.setBaseDir(baseDir.getAbsolutePath());Connector connector = new Connector(this.protocol);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);//将配置好的Tomcat传入进去,返回一个EmbeddedServletContainer;并且启动Tomcat服务器return getTomcatEmbeddedServletContainer(tomcat);}
public TomcatEmbeddedServletContainer(Tomcat tomcat, boolean autoStart) {Assert.notNull(tomcat, "Tomcat Server must not be null");this.tomcat = tomcat;//端口不为0,则自动启动this.autoStart = autoStart;initialize();}
private void initialize() throws EmbeddedServletContainerException {TomcatEmbeddedServletContainer.logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));synchronized (this.monitor) {try {addInstanceIdToEngineName();try {// Remove service connectors to that protocol binding doesn't happen// yetremoveServiceConnectors();// 启动Tomcat服务this.tomcat.start();// We can re-throw failure exception directly in the main threadrethrowDeferredStartupExceptions();Context context = findContext();try {ContextBindings.bindClassLoader(context, getNamingToken(context),getClass().getClassLoader());}catch (NamingException ex) {// Naming is not enabled. Continue}// Unlike Jetty, all Tomcat threads are daemon threads. We create a// blocking non-daemon to stop immediate shutdownstartDaemonAwaitThread();}catch (Exception ex) {containerCounter.decrementAndGet();throw ex;}}catch (Exception ex) {throw new EmbeddedServletContainerException("Unable to start embedded Tomcat", ex);}}}

(4)对嵌入式容器的配置修改是如何生效的?

主要是通过ServerProperties、EmbeddedServletContainerCustomizer来进行设置的

EmbeddedServletContainerCustomizer:定制器帮我们修改了Servlet容器的配置

(5)容器中导入了EmbeddedServletContainerCustomizerBeanPostProcessor

@Override//初始化之前public Object postProcessBeforeInitialization(Object bean, String beanName)throws BeansException {//如果当前初始化的是一个ConfigurableEmbeddServletContainer类型的组件if (bean instanceof ConfigurableEmbeddedServletContainer) {postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean);}return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName)throws BeansException {return bean;}private void postProcessBeforeInitialization(ConfigurableEmbeddedServletContainer bean) {//获取所有的定制器,调用每一个定制器的customize方法来给Servlet容器进行属性赋值for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) {customizer.customize(bean);}}private Collection<EmbeddedServletContainerCustomizer> getCustomizers() {if (this.customizers == null) {// 从容器中获取所有这个类型的组件:EmbeddedServletContainerCustomizer//定制Servlet容器,给容器中可以添加一个EmbeddedServletContainerCustomizer类型的组件this.customizers = new ArrayList<EmbeddedServletContainerCustomizer>(this.beanFactory.getBeansOfType(EmbeddedServletContainerCustomizer.class,false, false).values());Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE);this.customizers = Collections.unmodifiableList(this.customizers);}return this.customizers;}

主要步骤:

(1)SpringBoot根据导入的依赖情况,给容器中添加相应的EmbeddedServletContainerFactory[TomcatEmbeddedServletContainerFactory]

(2)容器中某个组件要创建对象就会惊动后置处理器:EmbeddedServletContainerCustomizerBeanPostProcessor;只要是嵌入式的Servlet容器工厂,后置处理器就会工作;

(3)后置处理器,从容器中获取所有的EmbeddedServletContainerCustomizer,调用定制器的定制方法

7、嵌入式Servlet容器启动原理

什么时候创建嵌入式的Servlet容器工厂?什么时候获取嵌入式的Servlet容器并启动Tomcat

获取嵌入式的Servlet容器工厂

(1)SpringBoot应用启动运行run方法

(2)refreshContext(context);SpringBoot刷新IOC容器,【创建IOC容器对象,并初始化容器,创建容器中的每一个组件】;如果是web应用创建AnnotationConfigEmbeddedWebApplicationContext,否则:AnnotationConfigApplicationContext

(3)refresh(context);刷新刚才创建好的IOC容器

@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.finishBeanFactoryInitialization(beanFactory);// 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();}}}

(4)onRefresh();Web的IOC容器重写了onRefresh方法

(5)Web的IOC容器会创建嵌入式的Servlet容器;createEmbeddedServletContainer();

(6)获取嵌入式的Servlet容器工厂:EmbeddedServletContainerFactory containerFactory = getEmbeddedServletContainerFactory();

从IOC容器中获取EmbeddedServletContainerFactory组件;TomcatEmbeddedServletContainerFactory创建对象,后置处理器一看是这个对象,就获取所有的定制器来先定制Servlet容器的相关配置;

(7)使用容器工厂获取嵌入式的Servlet容器:this.embeddedServletContainer = containerFactory.getEmbeddedServletContainer(getSelfInitializer());

(8)嵌入式的Servlet容器创建对象并启动Servlet容器;

先启动嵌入式的Servlet容器,再将IOC容器中剩下没有创建出的对象获取出来;

IOC容器启动创建嵌入式的Servlet容器

SpringBoot之配置嵌入式Servlet容器相关推荐

  1. springboot(七) 配置嵌入式Servlet容器

    github代码地址:https://github.com/showkawa/springBoot_2017/tree/master/spb-demo/spb-brian-query-service ...

  2. SpringBoot 配置嵌入式Servlet容器(tomcat,jetty,undertow)

    SpringBoot 默认打包方式为jar包,且可以自启动,就是因为它内嵌了Servlet容器. SpringBoot 默认使用嵌入式Servlet容器,SpringBoot 2.2.5 默认是 To ...

  3. SpringBoot配置嵌入式Servlet容器

    SpringBoot默认使用的是Tomcat作为嵌入式的Servlet容器,那么肯定会和外置的Tomcat有区别,那么就这些区别来谈一谈SpringBoot中对于容器的一些配置操作 如何定制和修改Se ...

  4. Spring Boot配置嵌入式Servlet容器的两种方法

    一.前言 SpringBoot默认使用Tomcat作为嵌入式的Servlet容器 二.如何定制和修改Servlet容器的相关配置: 1.修改和server有关的配置(ServerProperties[ ...

  5. Spring boot配置嵌入式Servlet容器

    Servlet容器 项目,打成war包,放在Tomcat启动 Tomcat就是一个Servlet容器 Spring boot 默认的嵌入了Servlet容器Tomcat 打开项目pom文件 右键Dia ...

  6. Spring Boot中配置嵌入式Servlet容器修改配置

    目录 基本概念 演示及源码 基本概念 如何修改Spring Boot的默认配置: 1. Spring Boot在自动配置很多组建的时候,先看容器中有没有用户自己配置的(@Bean,@Component ...

  7. 嵌入式Servlet容器

    配置嵌入式Servlet容器 ##Spring Boot里面内置了嵌入式的Servlet容器(tomcat) 点击pom.xml->右键->Diagrams->show Depend ...

  8. idea servlet自动配置web.xml_Spring Boot学习04_嵌入式Servlet容器自动配置原理

    在Spring Boot的自动配置包下,找到web模块中的servlet文件夹下的ServletWebServerFactoryConfiguration类 一.嵌入式Servlet容器默认的配置原理 ...

  9. SpringBoot 嵌入式Servlet容器

    一.嵌入式Servlet容器 切换嵌入式Servlet容器 默认支持的webServer :Tomcat, Jetty, or Undertow ServletWebServerApplication ...

最新文章

  1. win32下进程间通信方式之管道、邮件槽、剪切板、共享内存、消息、套接字、RPC、DDE等
  2. JS获取当前日期时间并定时刷新
  3. phpshe b2c商城系统配置nginx支持pathinfo和rewrite的写法
  4. Codeforces Round #490 (Div. 3)
  5. OpenSuSe使用相关
  6. nfs failed, reason given by server: Permission denied的离奇解决
  7. 使用Java 9向Javadoc搜索添加术语
  8. AS5040磁编码器使用笔记
  9. html 颜色在线取色器
  10. 谷歌邮箱lmap服务器填什么_常用邮箱SMTP服务器设置
  11. 模拟电子技术动画-PN结(动画是转的)内容再修改
  12. 查看苹果审核反馈的crash日志/崩溃日志
  13. c语言入门经典的作用,C语言入门经典
  14. ORA-01045:user C##KD lacks CREATE SESSION privilege;logon denied
  15. html项目符号实心圆圈,HTML基础 ul type 项目符号为圆圈与方块
  16. html5分镜头脚本范例,分镜头脚本范例
  17. 哒螨灵使用注意事项_哒螨灵的基础知识
  18. 修复Critical dependency: the request of a dependency is an expression警告
  19. Java中的XML解析
  20. c语言设计程序实现顺序冒泡_C语言学习 顺序程序设计

热门文章

  1. java for循环迭代_JAVA中的for-each循环与迭代
  2. python3 namedtuple_你不能低估的Python数据结构Namedtuple(二)
  3. java计算正方形_在地图计算圆的外接正方形,并返回左上顶点和右下顶点(java、javascript)...
  4. 怎么获取请求头中的origin信息_委托单位代办汇算清缴时无法获取到我的专项附加扣除信息怎么办?...
  5. android 联系人编辑界面,android – 以编程方式编辑联系人的姓名/电话号码
  6. java 继承thread_java线程-创建线程(继承 Thread 类)
  7. 简单介绍CentOS6升级glibc操作步骤
  8. poj1679(次小生成树)
  9. [JSOI2007]建筑抢修
  10. 牛客练习赛64 - B Dis2(树,基础图论)