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

简介: 【小家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从必选项已经成为可选项了)


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

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
JavaScript Java Maven
【SpringBoot(二)】带你认识Yaml配置文件类型、SpringMVC的资源访问路径 和 静态资源配置的原理!
SpringBoot专栏第二章,从本章开始正式进入SpringBoot的WEB阶段开发,本章先带你认识yaml配置文件和资源的路径配置原理,以方便在后面的文章中打下基础
760 4
|
XML Java 应用服务中间件
【SpringBoot(一)】Spring的认知、容器功能讲解与自动装配原理的入门,带你熟悉Springboot中基本的注解使用
SpringBoot专栏开篇第一章,讲述认识SpringBoot、Bean容器功能的讲解、自动装配原理的入门,还有其他常用的Springboot注解!如果想要了解SpringBoot,那么就进来看看吧!
942 2
|
人工智能 Java 机器人
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
Spring AI Alibaba集成Ollama,基于Java构建本地大模型应用,支持流式对话、knife4j接口可视化,实现高隐私、免API密钥的离线AI服务。
7797 2
基于Spring AI Alibaba + Spring Boot + Ollama搭建本地AI对话机器人API
存储 JSON Java
1106 0
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
3139 0
|
监控 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注册中心服务 构建商品
1650 3
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
1583 0
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)