前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring 全家桶之 Spring Boot 2.6.4(八)- 嵌入式 Servlet 容器(Part A)

Spring 全家桶之 Spring Boot 2.6.4(八)- 嵌入式 Servlet 容器(Part A)

作者头像
RiemannHypothesis
发布2022-09-26 15:52:50
4160
发布2022-09-26 15:52:50
举报
文章被收录于专栏:Elixir

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第23天,点击查看活动详情

一、修改Spring Boot 中内嵌Servlet容器的默认配置

Spring Boot提供了默认提供了内嵌的Tomcat,可以通过命令行运行jar包的方式运行Spring Boot应用,spring-boot-start-web依赖中包含了Tomcat依赖,最新版本为9.0.62。

image.png
image.png

以往通过Tomcat容器运行Spring应用时,可以通过修改Tomcat的一些配置文件来修改Tomcat的运行状态,比如说端口号等,那么Spring Boot内嵌的Tomcat要如何修改?

有两种方式修改内置Tomcat的配置,第一种是在application.properties中添加tomcat配置和server配置

image.png
image.png

第二种方式是编写一个WebServerFactoryCustomizer来进行tomcat的配置,在SpringBoot1.x的时候使用的是EmbeddedServletContainerCustomizer到SpringBoot2.x后WebServerFactoryCustomizer替代了EmbeddedServletContainerCustomizer。

代码语言:javascript
复制
@Configuration
public class LilithMvcConfig implements WebMvcConfigurer {
    
    @Bean
    public WebServerFactoryCustomizer<ConfigurableWebServerFactory> customizer(){
        return factory -> {
            factory.setPort(8083);
        };
    }
}

注释application.properties中的配置,重新启动该应用

image.png
image.png

配置生效,tomcat在8083端口启动

这两种配置的优先级是怎样的?

在application.properties中配置

代码语言:javascript
复制
server.port=8081
server.servlet.context-path=/servlet

保持WebServerFactoryCustomizer中配置的端口不变,重启应用

image.png
image.png

控制台输出端口号为8083,路径为/servlet,可以确定重写WebServerFactoryCustomizer配置Tomcat的优先级更高,并且和application.properties是互补的。

二、Spring Boot中注册Servlet、Filter、Listener

在Java Web项目中,我们书写的Servlet、Filter、Listener组件都可以通过web.xml将这些组件配置到Tomcat容器中,那么在Spring Boot项目中使用内置Tomcat并且没有web.xml的情况如何注册这些组件?

Spring Boot为Java Web三大组件提供了通过XxxRegistrationBean的方式进行注册

ServletRegistrationBean注册Servlet

创建一个HalloServelet类继承HttpServlet类,并重写doGet()和doPost()方法

代码语言:javascript
复制
public class HalloServlet extends HttpServlet {

    // 处理get请求
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        resp.getWriter().write("Hallo Servlet");
    }
}

使用ServletRegisterBean,代替在web.xml中注册Servlet,在LilithMvcConfig中增加代码

代码语言:javascript
复制
// 注册Servlet
@Bean
public ServletRegistrationBean<HalloServlet> halloServletServletRegistrationBean(){
    ServletRegistrationBean registrationBean = new ServletRegistrationBean();
    registrationBean.setServlet(new HalloServlet());
    registrationBean.setUrlMappings(Collections.singleton("/hallo"));
    return registrationBean;
}

重启应用,在浏览器访问/hallo

image.png
image.png

浏览器能够正常显示内容,自定义的Servlet成功注册。

FilterRegistrationBean注册Filter

首先自定义一个LilithFilter类实现Filter接口,在打印日志后放行请求

代码语言:javascript
复制
public class LilithFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

        System.out.println("LilithFilter running");
        chain.doFilter(request,response);
    }
}

在LilithMvcConfig配置类中通过FilterRegistrationBean注册自定义的LilithFilter,并在其中设置过滤器要拦截的请求路径

代码语言:javascript
复制
// 注册Filter
@Bean
public FilterRegistrationBean<LilithFilter> lilithFilterFilterRegistrationBean(){
    FilterRegistrationBean<LilithFilter> filterFilterRegistrationBean = new FilterRegistrationBean<>();
    filterFilterRegistrationBean.setFilter(new LilithFilter());
    // 设置拦截的请求路径
    filterFilterRegistrationBean.setUrlPatterns(Arrays.asList("/hallo"));

    return filterFilterRegistrationBean;
}

重启应用,在浏览器输入 /hallo

image.png
image.png

控制台输出自定义的LilithFilter类中的日志信息,自定义的LilithFilter注册成功并生效

在controller包中新增一个HiController,增加一个hi()方法,请求映射路径为/hi

代码语言:javascript
复制
@Controller
public class HiController {

    @RequestMapping("/hi")
    @ResponseBody
    public String hi(){
        return "Hi Lilith!";
    }
}

重启应用,浏览器访问/hi,看是否会拦截

image.png
image.png

控制台没有输出LilithFilter中设置的日志信息,说明没有被拦截,因为LilithFilter过滤器中没有设置拦截该请求,需要注意的是如果LilithFilter中没有设置拦截任何请求,默认拦截所有请求包括静态资源,但是不会jsp请求; /* 会拦截jsp请求。

ServletListenerRegistrationBean注册Listener

增加一个LilithListener类实现Listener接口,实现contextInitialized()方法和contextDestroyed()方法,并打印日志信

代码语言:javascript
复制
public class LilithListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("Web 应用启动了.......");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("Web 应用销毁了.......");
    }
}

在LilithMvcConfig配置类中通过ServletListenerRegistrationBean注册自定义的监听器LilithListener

代码语言:javascript
复制
@Bean
public ServletListenerRegistrationBean<LilithListener> servletListenerRegistrationBean(){
    ServletListenerRegistrationBean<LilithListener> servletListenerRegistrationBean = new ServletListenerRegistrationBean<>();
    servletListenerRegistrationBean.setListener(new LilithListener());
    return servletListenerRegistrationBean;
}

重启应用,查看控制台输出的日志信息

image.png
image.png

应用启动和关闭时都输出了自定义监听器LilithListener中定义的内容,说明自定义的监听器生效

Spring MVC的前端控制器DispatcherServlet就是通过这种方式来注册的,首先定义了DispatcherServlet类

image.png
image.png

接着通过DispatcherServletRegistrationBean注册了DispatcherServlet

image.png
image.png
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-04-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、修改Spring Boot 中内嵌Servlet容器的默认配置
  • 二、Spring Boot中注册Servlet、Filter、Listener
    • ServletRegistrationBean注册Servlet
      • FilterRegistrationBean注册Filter
        • ServletListenerRegistrationBean注册Listener
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档