【小家Spring】SpringBoot中使用Servlet、Filter、Listener三大组件的三种方式以及原理剖析

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【小家Spring】SpringBoot中使用Servlet、Filter、Listener三大组件的三种方式以及原理剖析

前提概要


web开发使用Controller基本能解决大部分的需求,但是有时候我们也需要使用Servlet,因为相对于拦截和监听来说,有时候原生的还是比较好用的。


因此本文就主要介绍web三大组件Servlet、Filter、Listener在SpringBoot中的使用做个介绍。本文重点做使用介绍,以及剖析SpringBoot是如何支持和解析这些方式的


Spring boot 的主 Servlet 为 DispatcherServlet,其默认的url-pattern为“/”。也许我们在应用中还需要定义更多的Servlet,该如何使用SpringBoot来完成呢?


三种方式


本文主要以使用Servelt为例子进行讲解,使用其余组件的方式也差不多。差异性比较大的地方我会尽量指出来,请举一反三


方式一: @ServletComponentScan 扫描的方式(推荐)


看看这个注解的javadoc

 * Enables scanning for Servlet components ({@link WebFilter filters}, {@link WebServlet
 * servlets}, and {@link WebListener listeners}). Scanning is only performed when using an
 * embedded web server.

     从javadoc中可以看出,该扫描的方式只支持嵌入式的web容器

使用此种扫描方式,显然是基于Servlet3.0的注解的方式。而该注解的解析由SpringBoot提供的@ServletComponentScan来驱动的。


案例如下:

@ServletComponentScan
@SpringBootApplication
public class Boot2Demo1Application {
    public static void main(String[] args) {
        SpringApplication.run(Boot2Demo1Application.class, args);
    }
}
/**
 * @author fangshixiang
 * @description
 * @date 2019-01-28 14:39
 */
@WebServlet(urlPatterns = "/servlet/demo", asyncSupported = false)
public class DemoServlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
        System.out.println("init my servlet");
        super.init();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("this is my servlet");
        super.doGet(req, resp);
    }
}


请求地址:http://localhost:8080/servlet/demo


控制台输出:

init my servlet
this is my servlet


有的朋友可能会问:为毛init方法也是此时才输出呢???为了答疑,这里之直接贴出来答案吧:


init 方法是随 Servlet 实例化而被调用的,因为 load-on-startup 就是用来设置Servlet 实例化时间的。因此,init 方法执行的时刻有两种:


  • load-on-startup 的值大于等于0,则伴随 Servlet 实例化后执行。
  • load-on-startup 的值小于0 或者 不配置(默认行为), 则在第一次 Servlet 请求的时候执行。


备注:看下面启动日志

2019-01-28 15:51:40.926  INFO 16144 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet com.sayabc.boot2demo1.servlet.DemoServlet mapped to [/servlet/demo]


可以看出,这种方式的底层原理还是转换成了ServletRegistrationBean,从而交给Spring容器管理了。同理:另外两大组件可以参照这个方式来定义和书写。


此方式优点:完全还原了源生servlet、filter、listener等功能,程序员自己也很方便的、更加细粒度。


方式二:通过ServletRegistrationBean进行组件注册


依托于SpringBoot提供的三个Bean:

ServletRegistrationBean
FilterRegistrationBean
ServletListenerRegistrationBean


实例代码:


    @Bean
    public ServletRegistrationBean MyServlet1() {
        return new ServletRegistrationBean(new DemoServlet(), "/servlet/*");
    }


访问路径:http://localhost:8080/servlet/demo控制台有对应日志输出(显然这种方式,init方法不会再执行了,因为自己new的嘛);


启动日志如下:


2019-01-28 15:59:37.412  INFO 14332 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet demoServlet mapped to [/servlet/*]

1

优点:内部可以直接@Autowired注入Spring的Bean,也可配合@Order调整优先级

方式三:@Component


采用此种方式是最简单的方式。Spring Boot也非常友好的给支持了。

示例:

@Component
public class DemoServlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
        System.out.println("init my servlet");
        super.init();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("this is my servlet");
        super.doGet(req, resp);
    }
}


日志输出:

2019-01-28 17:20:19.601  INFO 8756 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet demoServlet mapped to [/]


显然可以看出,直接使用@Component虽然方便,但是无法自定义urlPatterns,还是收到很多局限的。


备注:别想着这么做能达到效果(虽然我建议SpringBoot支持,哈哈

@Component
@WebServlet(urlPatterns = "/servlet/demo", asyncSupported = false)
public class DemoServlet extends HttpServlet {}


这样直接做是不生效的。还是只能映射到跟路径。因为@WebServlet等注解是依赖于

@ServletComponentScan才能驱动的,因此此种方式虽然方便,但是还是有很多局限性的。


但是,但是,对应Filter,一般我们都希望他拦截所有的请求,因此这么来做是很方便的。比如TokenFilter



@Order(1)
@Component
public class TokenFilter implements Filter{}


这样默认拦截的路径为:Mapping filter: 'tokenFilter' to: [/*],从而会过滤所有的请求。


小知识点:

< url-pattern>/</url-pattern>  会匹配到/login这样的路径型url,不会匹配到模式为*.jsp这样的后缀型url
< url-pattern>/*</url-pattern> 会匹配所有url:路径型的和后缀型的url(包括/login,*.jsp,*.js和*.html等)

所以如果以后发现总是有404错误的时候,别忘了check一下 /的配置是否是/*.


优点:内部可以直接@Autowired注入Spring的Bean,也可配合@Order调整优先级

简单总结

虽然Spring已经足够强大,几乎可以屏蔽我们对Servlet的Api。(Spring4以及以下版本的底层原理还是Servlet技术,但到了Spring5以后,servlet从必选项已经成为可选项了)


但是有的时候我们自己使用原生的方案更为妥当,因此本文针对于此提出一些方案和原理分析,仅供参考

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
2月前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
47 0
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
295 2
|
4月前
|
JavaScript Java 容器
servlet过滤器Filter简要回顾-过滤请求字符编码,/和/*和/**的区别
本文简要回顾了Servlet过滤器Filter的概念和使用,通过实例演示了如何创建过滤器以过滤请求字符编码,并解释了在web.xml中配置过滤器时使用`/`、`/*`和`/**`的区别。
servlet过滤器Filter简要回顾-过滤请求字符编码,/和/*和/**的区别
|
27天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
1月前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
106 14
|
2月前
|
Java Spring
SpringBoot自动装配的原理
在Spring Boot项目中,启动引导类通常使用`@SpringBootApplication`注解。该注解集成了`@SpringBootConfiguration`、`@ComponentScan`和`@EnableAutoConfiguration`三个注解,分别用于标记配置类、开启组件扫描和启用自动配置。
69 17
|
2月前
|
Java 容器
springboot自动配置原理
启动类@SpringbootApplication注解下,有三个关键注解 (1)@springbootConfiguration:表示启动类是一个自动配置类 (2)@CompontScan:扫描启动类所在包外的组件到容器中 (3)@EnableConfigutarion:最关键的一个注解,他拥有两个子注解,其中@AutoConfigurationpackageu会将启动类所在包下的所有组件到容器中,@Import会导入一个自动配置文件选择器,他会去加载META_INF目录下的spring.factories文件,这个文件中存放很大自动配置类的全类名,这些类会根据元注解的装配条件生效,生效
|
6月前
|
Java 应用服务中间件 开发者
Java面试题:解释Spring Boot的优势及其自动配置原理
Java面试题:解释Spring Boot的优势及其自动配置原理
136 0
|
3月前
|
Java Spring 容器
springboot @RequiredArgsConstructor @Lazy解决循环依赖的原理
【10月更文挑战第15天】在Spring Boot应用中,循环依赖是一个常见问题,当两个或多个Bean相互依赖时,会导致Spring容器陷入死循环。本文通过比较@RequiredArgsConstructor和@Lazy注解,探讨它们解决循环依赖的原理和优缺点。@RequiredArgsConstructor通过构造函数注入依赖,使代码更简洁;@Lazy则通过延迟Bean的初始化,打破创建顺序依赖。两者各有优势,需根据具体场景选择合适的方法。
169 4
|
4月前
|
Java 应用服务中间件 API
Vertx高并发理论原理以及对比SpringBoot
Vertx 是一个基于 Netty 的响应式工具包,不同于传统框架如 Spring,它的侵入性较小,甚至可在 Spring Boot 中使用。响应式编程(Reactive Programming)基于事件模式,通过事件流触发任务执行,其核心在于事件流 Stream。相比多线程异步,响应式编程能以更少线程完成更多任务,减少内存消耗与上下文切换开销,提高 CPU 利用率。Vertx 适用于高并发系统,如 IM 系统、高性能中间件及需要较少服务器支持大规模 WEB 应用的场景。随着 JDK 21 引入协程,未来 Tomcat 也将优化支持更高并发,降低响应式框架的必要性。
106 6
Vertx高并发理论原理以及对比SpringBoot