• 18. 注入 Servlet、Filter、Listener



    18.1 官方文档

    18.2 基本介绍

    1. 考虑到实际开发业务非常复杂和兼容,Spring-Boot 支持将 Servlet、Filter、Listener 注入 Spring 容器,成为 Spring bean
    2. 也就是说 Spring-Boot 开放了和原生 WEB 组件(Servlet、Filter、Listener)的兼容

    18.3 应用实例 1-使用注解方式注入

    18.3.1 需求说明

    • 演示通过注解方式注入 Servlet、Filter、Listener

    18.3.2 应用实例-实现

    18.3.2.1 注入 Servlet

    1. 创建 com/xjs/springboot/servlet/Servlet_.java
    package com.xjs.springboot.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     *
     * 1. 通过继承 HttpServlet 来开发原生的Servlet
     * 2. @WebServlet 标识将 Servlet_ 对象/Bean 注入到容器中
     * 3. urlPatterns = {"/servlet01", "/servlet02"} 对该 servlet配置了 url-pattern [映射路径]
     * 4. 特别提示:注入的原生的 Servlet_ 不会被 springboot 的拦截器拦截
     *    因为 我们这里的 Servlet_ 和 SpringMVC 的前端控制器-DispatcherServlet 属于同一级别
     *    当请求发来,就直接走到这里的 Servlet_ 而不会经过 Springmvc的那套机制
     *    ==> 回顾一下 前面学习的 过滤器和拦截器的区别
     *
     * 5. 对于开发的原生的Servlet,需要使用 @ServletComponentScan指定要扫描的原生Servlet包,
     *    才会注入到 spring 容器中
     */
    @WebServlet(urlPatterns = {"/servlet01", "/servlet02"})
    public class Servlet_ extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.getWriter().write("hello, Servlet_");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    1. 修改 com/xjs/springboot/Application.java ,加入@ServletComponentScan

    在这里插入图片描述

    package com.xjs.springboot;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.web.servlet.ServletComponentScan;
    import org.springframework.context.ConfigurableApplicationContext;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     */
    //要求扫描 com.xjs.springboot 包/子包 下的原生的方式 注入Servlet
    @ServletComponentScan(basePackages = "com.xjs.springboot")
    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
    
            ConfigurableApplicationContext ioc = SpringApplication.run(Application.class, args);
    
            System.out.println("hello");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    在这里插入图片描述

    1. 完成测试
    • 浏览器 http://localhost:8080/servlet01

    在这里插入图片描述


    • 浏览器 http://localhost:8080/servlet02

    在这里插入图片描述


    18.3.2.2 注入 Filter

    1. 创建 com/xjs/springboot/servlet/Filter_.java
    package com.xjs.springboot.servlet;
    
    import lombok.extern.slf4j.Slf4j;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import javax.servlet.http.HttpServletRequest;
    import java.io.IOException;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     *
     * 1. @WebFilter 表示 Filter_ 是一个过滤器,并注入到容器
     * 2. urlPatterns = {"/css/*", "/images/*"} 当请求 /css/目录资源 或者 /images/目录下资源 的时候会经过该过滤器
     * 3. 这里直接放行,放行后再经过拦截器 ,拦截器是否拦截需要根据拦截器的拦截规则
     */
    @WebFilter(urlPatterns = {"/css/*", "/images/*"})
    @Slf4j
    public class Filter_ implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            log.info("Filter_ init() 方法被调用...");
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            log.info("Filter_ doFilter() 方法被调用...");
            //为了方便观察过滤器处理的资源,这里我们输出一下 uri
            String uri = ((HttpServletRequest) servletRequest).getRequestURI();
            log.info("过滤器处理的uri={}", uri);
            //这里直接放行
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
            log.info("Filter_ destroy() 方法被调用...");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    1. 创建 static/css/t.css,作为测试文件

    在这里插入图片描述

    1. 完成测试,注意观察后台,浏览器 : http://localhost:8080/css/t.css

    在这里插入图片描述


    在这里插入图片描述

    注意事项:

    • 过滤器配置的 urlPatterns 也会经过 Spring-Boot 拦截器(根据拦截器的规则)
    • 在 servlet 匹配全部是 /* ,在 Spring-Boot 是/**

    在这里插入图片描述

    在这里插入图片描述

    18.3.2.3 注入 Listener

    1. 创建 com/xjs/springboot/servlet/Listener_.java
    package com.xjs.springboot.servlet;
    
    import lombok.extern.slf4j.Slf4j;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     */
    @Slf4j
    @WebListener
    public class Listener_ implements ServletContextListener {
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
    
            //这里可以加入项目初始化的相关业务代码
            log.info("Listener_ contextInitialized() 项目初始化ok~");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            //这里也可以加入相应代码
            log.info("Listener_ contextDestroyed() 项目销毁ok~");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    1. 完成测试,启动项目,观察后台输出

    在这里插入图片描述

    18.4 应用实例 2-使用 RegistrationBean 方式注入

    18.4.1 需求说明

    • 演示使用 RegistrationBean 注入 Servlet、Filter、Listener

    18.4.2 应用实例-实现

    1. 创建 com/xjs/springboot/config/RegisterConfig_.java
    package com.xjs.springboot.config;
    
    import com.xjs.springboot.servlet.Filter_;
    import com.xjs.springboot.servlet.Listener_;
    import com.xjs.springboot.servlet.Servlet_;
    import org.springframework.boot.web.servlet.FilterRegistrationBean;
    import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
    import org.springframework.boot.web.servlet.ServletRegistrationBean;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.Arrays;
    
    /**
     * @Author: 谢家升
     * @Version: 1.0
     * @Configuration 表示 RegisterConfig_ 是一个配置类
     * proxyBeanMethods = true : 默认是单例返回Bean [保证每个@Bean 方法被调用多少次返回的组件都是单实例的, 是代理方式]
     */
    @Configuration(proxyBeanMethods = true)
    public class RegisterConfig_ {
    
        //使用 RegistrationBean 注入 Servlet
        @Bean
        public ServletRegistrationBean servlet_() {
            //创建原生的 Servlet对象
            Servlet_ servlet_ = new Servlet_();
    
            //把 servlet_对象关联到 ServletRegistrationBean 对象中
            // "/servlet01","servlet02" 就是注入的 servlet的 uri-pattern
            return new ServletRegistrationBean(servlet_, "/servlet01", "/servlet02");
        }
    
        //使用 RegistrationBean 注入 Filter
        @Bean
        public FilterRegistrationBean filter_() {
    
            //创建原生的 Filter对象
            Filter_ filter_ = new Filter_();
    
            FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(filter_);
            //设置Filter的 url-pattern
            filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*", "/images/*"));
    
            return filterRegistrationBean;
        }
    
    
        //使用 RegistrationBean 注入 Listener
        @Bean
        public ServletListenerRegistrationBean listener_() {
            //创建原生的 Listener_对象
            Listener_ listener_ = new Listener_();
    
            return new ServletListenerRegistrationBean(listener_);
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    1. 去掉相关的注解,再次完成测试

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    18.5 注意事项和细节说明

    18.5.1 请求 Servlet 时,为什么不会到达拦截器

    1. 请求 Servlet 时,不会到达 DispatherServlet,因此也不会达到拦截器

    2. 原因分析

      ● 注入的 Servlet 会存在 Spring 容器中
      ● DispatherServlet 也存在 Spring 容器中


    在这里插入图片描述


    1. 回顾一下 Tomcat 在对 Servlet url 匹配的原则,多个 servlet 都能处理到同一层路径,精确优先原则/最长前缀匹配原则
    2. 在看看 spring 容器的 debug 图

    在这里插入图片描述

    在这里插入图片描述

    1. 在 SpringBoot 中,去调用@Controller 目标方法 是按照 DispatherServlet 分发匹配的机制,回顾一下自己实现 SpringMVC 的底层机制的程序

    18.5.2 源码分析

    1. DispatcherServletAutoConfiguration 完成对 DispatcherServlet 自动配置
    2. 下面执行流程分析

    在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    • 观察一下单例池中 dispatcherServletRegistration 和 DispatcherServlet 之间的关联关系

    在这里插入图片描述

    在这里插入图片描述

  • 相关阅读:
    K8S(一)
    阿里巴巴战略放弃“天猫香港”,专注于改善跨境电子商务
    真正“搞”懂HTTP协议02之空间穿梭
    Postman的简单使用
    ffmpeg 查看本地摄像头和麦克风设备名称
    通过函数来提交表单数据,并且携带参数
    Echarts 有数据,但图不显示(完美解决方案)
    【题解】蒙德里安的梦想
    【Python爬虫实战】 不生产小说,只做网站的搬运工,太牛逼了~(附源码)
    Python深度学习13——Keras模型的可视化(神经网络结构图)
  • 原文地址:https://blog.csdn.net/weixin_60766221/article/details/126306447