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

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

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

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

f7e6067db52b462f9d015fef23d5cea6_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

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

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

4a82f4c0ec3a4148abaf932b2771bd3c_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

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

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

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

ec50ba063fb340339eeceb4d794c794f_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

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

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

在application.properties中配置

server.port=8081
server.servlet.context-path=/servlet
复制代码

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

d73b55870d924bbdaf6b32908ac2dc0f_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.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()方法

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中增加代码

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

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

fca53eea533a4caba7a91a77a75685a3_tplv-k3u1fbpfcp-zoom-in-crop-mark_4536_0_0_0.png

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

FilterRegistrationBean注册Filter

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

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,并在其中设置过滤器要拦截的请求路径

// 注册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

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

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

@Controller
public class HiController {
    @RequestMapping("/hi")
    @ResponseBody
    public String hi(){
        return "Hi Lilith!";
    }
}
复制代码

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

image.png

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

ServletListenerRegistrationBean注册Listener

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

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

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

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

image.png

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

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

image.png

接着通过DispatcherServletRegistrationBean注册了DispatcherServlet

image.png


相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
相关文章
|
6月前
|
前端开发 Java 应用服务中间件
《深入理解Spring》 Spring Boot——约定优于配置的革命者
Spring Boot基于“约定优于配置”理念,通过自动配置、起步依赖、嵌入式容器和Actuator四大特性,简化Spring应用的开发与部署,提升效率,降低门槛,成为现代Java开发的事实标准。
|
6月前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
6月前
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
669 2
|
7月前
|
人工智能 Java 机器人
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
Spring AI Alibaba集成Ollama,基于Java构建本地大模型应用,支持流式对话、knife4j接口可视化,实现高隐私、免API密钥的离线AI服务。
5949 2
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
存储 JSON Java
798 0
|
7月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
2441 0
|
8月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1221 3
|
前端开发 Java Maven
Spring 和 Spring Boot 之间的比较
本文对比了标准Spring框架与Spring Boot的区别,重点分析两者在模块使用(如MVC、Security)上的差异。Spring提供全面的Java开发基础设施支持,包含依赖注入和多种开箱即用的模块;而Spring Boot作为Spring的扩展,通过自动配置、嵌入式服务器等功能简化开发流程。文章还探讨了两者的Maven依赖、Mvc配置、模板引擎配置、启动方式及打包部署等方面的异同,展示了Spring Boot如何通过减少样板代码和配置提升开发效率。总结指出,Spring Boot是Spring的增强版,使应用开发、测试与部署更加便捷高效。
1530 11