配置嵌入式Servlet容器

SpringBoot默认使用TomCat作为嵌入式的Servlet容器
在这里插入图片描述

  1. 如何定制和修改Servlet容器的相关配置

    1. 修改和Servlet有关的配置(ServerProperties)
    //通用的Servlet容器设置
    server.xxx=
    //Tomcat的设置
    server.tomcat.xxx=
    
    1. 编写一个WebServerFactoryCustomizer
    @Bean
     public WebServerFactoryCustomizer webServerFactoryCustomizer(){
         return new WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>(){
    
             //定制嵌入式的Servlet容器相关的规则
             @Override
             public void customize(ConfigurableServletWebServerFactory factory) {
                 factory.setPort(8083);
             }
         };
     }
    
  2. 注册Servlet三大组件
    由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的Web项目,没有web.xml文件

    1. ServletRegistrationBean
    public class MyServlet extends HttpServlet {
         @Override
         protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             resp.getWriter().write("Hello MyServlet");
         }
    
         @Override
         protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
             this.doPost(req, resp);
         }
     }
    
    @Bean
     public ServletRegistrationBean myServlet(){
         ServletRegistrationBean<Servlet> registrationBean = new ServletRegistrationBean<>(new MyServlet(),"/myServlet");
         return registrationBean;
     }
    
    1. FilterRegistration
    public class MyFilter implements Filter {
         @Override
         public void init(FilterConfig filterConfig) throws ServletException {
    
         }
    
         @Override
         public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
             System.out.println("MyFilter process....");
             filterChain.doFilter(servletRequest,servletResponse);
         }
    
         @Override
         public void destroy() {
    
         }
     }
    
    @Bean
     public FilterRegistrationBean myFilter(){
         FilterRegistrationBean<Filter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
         filterFilterRegistrationBean.setFilter(new MyFilter());
         filterFilterRegistrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
         return filterFilterRegistrationBean;
     }
    
    1. ServletListenerRegistrationBean
    public class MyListener implements ServletContextListener {
         @Override
         public void contextInitialized(ServletContextEvent sce) {
             System.out.println("contextInitialized...web应用启动");
         }
    
         @Override
         public void contextDestroyed(ServletContextEvent sce) {
             System.out.println("contextDestroyed...当前web项目销毁");
         }
     }
    
    @Bean
     public ServletListenerRegistrationBean myListener(){
         ServletListenerRegistrationBean<EventListener> eventListenerServletListenerRegistrationBean = new ServletListenerRegistrationBean<>(new MyListener());
         return eventListenerServletListenerRegistrationBean;
     }
    
    1. SpringBoot帮我们自动配置SpringMVC的时候,自动注册SpringMVC的前端控制器;DispatcherServlet
    @Bean(
         name = {"dispatcherServletRegistration"}
     )
     @ConditionalOnBean(
         value = {DispatcherServlet.class},
         name = {"dispatcherServlet"}
     )
     public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet, WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
         DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet, webMvcProperties.getServlet().getPath());
         //默认拦截:"/" 所以请求,包括静态资源,但是不拦截jsp请求;"/*"会拦截jsp
         //可以通过server.servletPath来修改SpringMVC前端控制器默认拦截的请求路径
         registration.setName("dispatcherServlet");
         registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
         multipartConfig.ifAvailable(registration::setMultipartConfig);
         return registration;
     }
    

SpringBoot能不能支持其他的Servlet容器

在这里插入图片描述

  1. TomCat(默认)
  2. Jetty
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

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

<!-- 引入其他的Servlet容器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>

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

嵌入式Servlet容器启动原理

使用外置的Servlet容器

  1. 嵌入式Servlet容器:jar

    1. 优点:简单,便捷
    2. 缺点:默认不支持JSP、优化定制比较复杂(使用定制器【ServerProperties、自定义WebServerFactoryCustomizer】),自己编写嵌入式Servlet容器创建工厂【ConfigurableServletWebServerFactory 】)
  2. 外置的Servlet容器:外面安装Tomcat–应用war包的方式打包

    1. 必须创建一个war项目
    2. 将嵌入式Tomcat指定为provided
    <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-tomcat</artifactId>
         <scope>provided</scope>
     </dependency>
    
    1. 必须编写一个SpringBootServletInitializer,并调用configure方法
    public class ServletInitializer extends SpringBootServletInitializer {
    
         @Override
         protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
             //传入SpringBoot应用主程序
             return application.sources(DemoApplication.class);
         }
    
     }
    
    1. 启动服务器就可以使用
  3. 原理

    1. jar包:执行Spring Boot主类的main方法,启动IOC容器,创建嵌入式的Servlet容器

    2. war包:启动服务器,服务器启动SpringBoot应用【SpringBootServletInitializer】,启动ioc容器

    3. 规则:

      1. 服务器启动(web应用启动)会创建当前web应用里面每一个jar包里面ServletContainerInitializer实例
      2. ServletContainerInitializer的实现放在jar包的META-INF/service文件夹下,有一个名为javax.servlet.ServletContainerInitializer的文件,内容就是ServletContainerInitializer实现类的全类名
      3. 还可以使用@HandlesTypes,在应用启动的时候加载我们感兴趣的类
    4. 流程

      1. 启动Tomcat

      2. org\springframework\spring-web\5.3.1\spring-web-5.3.1.jar!\META-INF\services\javax.servlet.ServletContainerInitializer;文件内容:org.springframework.web.SpringServletContainerInitializer

      3. SpringServletContainerInitializer将@HandlesTypes({WebApplicationInitializer.class})标注的所有这个类型的类都传入到onStartup的Set<Class<?>>,为这些WebApplicationInitializer类型的类创建实例

      4. 每一个WebApplicationInitializer都调用自己的onStartup
        在这里插入图片描述

      5. 相当于我们的SpringBootServletInitializer的类会被创建对象,并执行onStartup方法

      6. SpringBootServletInitializer示例执行onStartup的时候会createRootApplicationContext创建容器

      protected WebApplicationContext createRootApplicationContext(ServletContext servletContext) {
          //创建SpringApplicationBuilder构建器
          SpringApplicationBuilder builder = this.createSpringApplicationBuilder();
          builder.main(this.getClass());
          ApplicationContext parent = this.getExistingRootWebApplicationContext(servletContext);
          if (parent != null) {
              this.logger.info("Root context already created (using as parent).");
              servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, (Object)null);
              builder.initializers(new ApplicationContextInitializer[]{new ParentContextApplicationContextInitializer(parent)});
          }
      
          builder.initializers(new ApplicationContextInitializer[]{new ServletContextApplicationContextInitializer(servletContext)});
          builder.contextFactory((webApplicationType) -> {
              return new AnnotationConfigServletWebServerApplicationContext();
          });
          //调用configure方法,子类重写了这个方法,将SpringBoot的主程序类传入进来
          builder = this.configure(builder);
          builder.listeners(new ApplicationListener[]{new SpringBootServletInitializer.WebEnvironmentPropertySourceInitializer(servletContext)});
          //使用builder创建一个Spring应用
          SpringApplication application = builder.build();
          if (application.getAllSources().isEmpty() && MergedAnnotations.from(this.getClass(), SearchStrategy.TYPE_HIERARCHY).isPresent(Configuration.class)) {
              application.addPrimarySources(Collections.singleton(this.getClass()));
          }
      
          Assert.state(!application.getAllSources().isEmpty(), "No SpringApplication sources have been defined. Either override the configure method or add an @Configuration annotation");
          if (this.registerErrorPageFilter) {
              application.addPrimarySources(Collections.singleton(ErrorPageFilterConfiguration.class));
          }
      
          application.setRegisterShutdownHook(false);
          //启动Spring应用
          return this.run(application);
      }
      
      1. Spring的应用就启动了,并且创建IOC容器
      2. 先启动Servlet容器,在启动SpringBoot应用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一大岐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值