【spring boot2】第8篇:spring boot 中的 servlet 容器及如何使用war包部署

嵌入式 servlet 容器

在 spring boot 之前的web开发,我们都是把我们的应用部署到 Tomcat 等servelt容器,这些容器一般都会在我们的应用服务器上安装好环境,但是 spring boot 中并不需要外部应用服务器安装这些servlet容器,spring boot自带了嵌入式的servlet容器。

如何修改和定制嵌入式servlet容器

  • 在application.yaml文件中配置修改
#修改服务端口号
server.port=8081
#配置统一请求路径
server.context‐path=/crud

#配置tomcat相关
server.tomcat.uri‐encoding=UTF‐8

这些配置相关的属性都定义在org.springframework.boot.autoconfigure.web.ServerProperties类中

  • 编写一个嵌入式的servlet容器的定制器来修改相关的配置
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

    @Override
    public void customize(ConfigurableServletWebServerFactory server) {
        server.setPort(9000);
    }
}
  • 直接定制具体的servlet容器配置,比如 tomcat 容器
@Configuration
public class ApplicationConfig implements WebMvcConfigurer {

    @Bean
    public ConfigurableServletWebServerFactory configurableServletWebServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        factory.setPort(8585);
        return factory;
    }
}

注册 Servlet、Filter、Listener

spring boot默认是以 jar 包的方式启动嵌入式的 servlet 容器来启动web应用,应用中并没有 web.xml 文件,我们注册 servlet, filter, 和 listener 三大组件可以使用以下方式

  • 利用ServletRegistrationBean注册 servlet

    • 定义自己的 servlet
    public class MyServlet extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            resp.getWriter().print("servlet doGet");
        }
    }
    • 给容器中注册自己的 servlet
    @Configuration
    public class ApplicationConfig implements WebMvcConfigurer {
    
        @Bean
        public ServletRegistrationBean myServlet() {
            ServletRegistrationBean servletRegistrationBean =
                    new ServletRegistrationBean(new MyServlet(), "/hello/servlet");
            return servletRegistrationBean;
        }
    }
  • 利用FilterRegistrationBean注册 filter

    • 定义 filter`
    public class MyFilter implements Filter {
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            System.out.println("do myFilter");
            chain.doFilter(request, response);
        }
    }
    • 容器中注册 filter
    @Configuration
    public class ApplicationConfig implements WebMvcConfigurer {
        @Bean
        public FilterRegistrationBean myFilter() {
            FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
            //注册自己的 filter
            filterRegistrationBean.setFilter(new MyFilter());
            //注册拦截路径
            filterRegistrationBean.setUrlPatterns(Arrays.asList("/hello", "/hello/servlet"));
            return filterRegistrationBean;
        }
    }

    访问 "/hello", "/hello/servlet"请求时拦截器就会起作用。

  • 利用ServletListenerRegistrationBean注册 listener

    • 定义一个listener
    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应用销毁");
        }
    }
    • 容器中注册listener
    @Configuration
    public class ApplicationConfig implements WebMvcConfigurer {
        @Bean
        public ServletListenerRegistrationBean myListener() {
            ServletListenerRegistrationBean<MyListener> listenerRegistrationBean =
                    new ServletListenerRegistrationBean(new MyListener());
            return listenerRegistrationBean;
        }
    }

切换其他 servlet 容器

spring boot 中默认使用的是 tomcat 容器,那么如何切换使用其他容器呢,比如 jetty。那么如何切换成其他的呢?只需要修改 pom.xml 文件

<!‐‐ 引入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>

使用外部 servlet 容器

部署项目的服务器安装 servlet 容器,比如 tomcat、jetty 容器,然后项目打成 war 包的形式进行部署
如何创建一个 war 包启动的 spring boot 项目呢?

  1. 创建一个war打包形式的web项目,其目录结构如下

【spring boot2】第8篇:spring boot 中的 servlet 容器及如何使用war包部署

  1. 修改 pom.xml 文件

    • 修改打包方式

      pom.xml 文件中的打包方式设置成 war 即可,            ```<packaging>war</packaging>```
    • 修改嵌入的 servlet 容器

      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-tomcat</artifactId>
          <scope>provided</scope>
      </dependency>
  2. 编写一个类继承 SpringBootServletInitializer
public class ServletInitializer extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SpringBootWarApplication.class);
    }
}

使用外部 servlet 容器原理

jar包和war的启动过程

  1. jar包: 执行spring boot 主类的main方法,启动ioc容器,然后创建嵌入式的servlet容器
  2. war包: 启动tomcat服务器,服务器启动spring boot应用,通过SpringBootServletInitializer实现,启动ioc容器

spring boot使用外部servlet过程

servlet3.0标准中规定

  • web应用启动会创建当前web应用里面每一个jar包里面ServletContainerInitializer类型的实例
  • ServletContainerInitializer的实现放在jar包的META-INF/services文件夹下,有一个名为javax.servlet.ServletContainerInitializer的文件,文件内容就是ServletContainerInitializer实现类的全类名
  • 使用@HandlesTypes注解在应用启动的时候加载我们需要的类

spring boot使用war启动原理

  • 重写SpringBootServletInitializerconfigure(SpringApplicationBuilder application)方法,调用SpringApplicationBuildersources(Class<?>... sources)方法
  • 启动原理

    • Servlet3.0标准ServletContainerInitializer扫描所有jar包中META- INF/services/javax.servlet.ServletContainerInitializer文件指定的类并加载
    • 加载spring web包下的org.springframework.web.SpringServletContainerInitializer
    • 扫描@HandleType(WebApplicationInitializer)`,即扫描WebApplicationInitializer的所有实现类
    • 加载SpringBootServletInitializer并运行onStartup方法
    • 加载@SpringBootApplication主类,启动容器

相关推荐