• SpringBoot-注入 Servlet、Filter、Listener


    SpringBoot-注入 Servlet、Filter、Listener

    1.官方文档

    1.文 档

    https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.developing-web-applications.embedded-container.servlets-filters-listeners

    2.基本介绍

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

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

    1.需求 : 演示通过注解方式注入 Servlet、Filter、Listener

    主启动类添加@ServletComponentScan,添加包扫描这样注入的servlet、filter、listener才能注入ioc容器

    image-20220813170717882

    需要注意的是注入ioc容器中的servlet,key为类的全路径,而注入的类型是ServletRegistrationBean.class

    image-20220813170412470

    去掉@ServletComponentScan包扫描,无法注入ioc容器

    image-20220813170447285

    2.应用实例-实现

    1.注入servlet

    1.创建src\main\java\com\llp\springboot\servlet\Servlet_.java

    /**
     * 1. 通过继承 HttpServlet 来开发原生的Servlet
     * 2. @WebServlet 标识将 Servlet_ 对象/bean注入到容器
     * 3. (urlPatterns = {"/servlet01","/servlet02"} ,对servlet配置了url-pattern
     * 4. 提示: 注入的原生的Servlet_ 不会被spring-boot的拦截器拦截
     * 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 {
            doPost(req,resp);
        }
    
        @Override
        protected void doPost(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

    2.修改主启动添加包扫描

    @SpringBootApplication
    //要求扫描com.llp.springboot 包/子包下的原生方式注入的Servlet
    @ServletComponentScan(basePackages = "com.llp.springboot")
    public class Application {
        public static void main(String[] args) {
            ConfigurableApplicationContext ioc = SpringApplication.run(Application.class, args);
            ServletRegistrationBean servletRegistrationBean = ioc.getBean("com.llp.springboot.servlet.Servlet_", ServletRegistrationBean.class);
            Servlet servlet = servletRegistrationBean.getServlet();
            System.out.println(servlet);
            System.out.println(ioc);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.测试

    image-20220813172132795

    2.注入filter

    1.创建src\main\java\com\hspedu\springboot\servlet\Filter_.java

    @Slf4j
    @WebFilter(urlPatterns = {"/css/*", "/images/*"})
    public class Filter_ implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            log.info("--Filter_ init--");
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            log.info("--Filter_ doFilter--");
            //为了方便观察过滤器处理的资源,我们输出一个uri
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            log.info("过滤器处理的uri={}", httpServletRequest.getRequestURI());
            //我们直接放行-实际开发中,根据自己的业务来决定如何处理
            chain.doFilter(request, response);
        }
    
        @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

    2.创建src\main\resources\static\css\t.css

    hello
    
    • 1

    3.测试http://localhost:8080/css/t.css

    image-20220813172611053

    3.注入Listener

    **ServletContextListener:**监听 ServletContext 创建或销毁(当我们Web 应用启动时,就会创建 ServletContext), 即生命周期监听,

    应用场景(1)加载初始化的配置文件;比如 spring 的配置文件 (2)任务调度(配合定时器 Timer/TimerTask)

    @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 项目销毁");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    测试

    image-20220813172946055

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

    1.需求 : 演示使用 RegistrationBean 注入 Servlet、Filter、Listener

    2.应用实例-实现

    通过配置类的方式注入,不需要添加@WebListener、@WebFilter、@WebServlet同时启动类的包扫描也是不需要的

    1.创建配置类

    /**
     * proxyBeanMethods = true : 默认是单例返回bean[保证每个@Bean 方法被调用多少次返回的组件都是 单实例的, 是代理方式]
     */
    @Configuration(proxyBeanMethods = true)
    public class RegisterConfig {
    
        //注入servlet
        @Bean
        public ServletRegistrationBean servletRegistrationBean(){
            return new ServletRegistrationBean(new Servlet_(),"/servlet01","/servlet02");
        }
    
        //注入filter
        @Bean
        public FilterRegistrationBean filterRegistrationBean(){
            FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
            filterRegistrationBean.setFilter(new Filter_());
            filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*", "/images/*"));
            return filterRegistrationBean;
        }
    
        //注入listener
        @Bean
        public ServletListenerRegistrationBean servletListenerRegistrationBean(){
            ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
            servletListenerRegistrationBean.setListener(new Listener_());
            return servletListenerRegistrationBean;
        }
    
    }
    
    • 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

    2.创建servlet、listener、filter

    servlet

    /**
     * 1. 通过继承 HttpServlet 来开发原生的Servlet
     * 2. @WebServlet 标识将 Servlet_ 对象/bean注入到容器
     * 3. (urlPatterns = {"/servlet01","/servlet02"} ,对servlet配置了url-pattern
     * 4. 提示: 注入的原生的Servlet_ 不会被spring-boot的拦截器拦截
     * 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 {
            doPost(req,resp);
        }
    
        @Override
        protected void doPost(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

    filter

    /**
     * 开发Filter 并注入
     *
     * 1. @WebFilter 表示Filter_是一个过滤器,并注入容器
     * 2. urlPatterns = {"/css/*", "/images/*"} 当请求  /css/目录资源或者 /images/目录下资源的时候,会经过该过滤器
     * 3. 直接放行后,在经过拦截器, 拦截器是否拦截要根据拦截器的拦截规则
     */
    @Slf4j
    //@WebFilter(urlPatterns = {"/css/*", "/images/*"})
    public class Filter_ implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            log.info("--Filter_ init--");
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            log.info("--Filter_ doFilter--");
            //为了方便观察过滤器处理的资源,我们输出一个uri
            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
            log.info("过滤器处理的uri={}", httpServletRequest.getRequestURI());
            //我们直接放行-实际开发中,根据自己的业务来决定如何处理
            chain.doFilter(request, response);
        }
    
        @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

    listener

    @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 项目销毁");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    5.注意事项和细节说明

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

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

    √ 注入的 Servlet 会存在 Spring 容器

    √ DispatherServlet 也存在 Spring 容器

    image-20220813142113324

    1. Tomcat 在对 Servlet url 匹配的原则, 多个 servlet 都能处理到 同一层路径, 精确优先原则/最长前缀匹配原则.
    2. 精确路径 > 目录路径 > 扩展名路径 > /* > /
    3. 在看看 spring 容器的debug图

    image-20220813145658660

    ​ 6.在 SpringBoot 中, 去调用@Controller 目标方法 是按照 DispatherServlet 分发匹配的机制

    2.源码分析

    1. DispatcherServletAutoConfiguration 完成对 DispatcherServlet 自动配置

    2. 下面执行流程分析

    image-20220813174537037

    image-20220813174613659

    6.拦截器和过滤器的区别

    image-20220813180320105

    1.过滤器是拦截tomcat对servlet的请求

    2.拦截器是拦截servlet到controller的请求分发

    3.过滤器不会拦截请求转发,拦截器会拦截请求转发。因为请求转发由servlet在服务端发起,过滤器不会进行拦截

    4.controller层的请求由dispatcherServlet进行分发,而dispatcherServlet是一个servlet

  • 相关阅读:
    H5画布绘制渐变
    对享元模式的理解
    perf性能分析工具使用分享
    【人工智能】机器学习入门之监督学习(一)有监督学习
    《Java并发编程的艺术》——锁(笔记)
    条条大路通罗马-面试题(一)
    docker安装以及部署
    基于随机森林实现特征选择降维及回归预测(Matlab代码实现)
    认识通讯协议——TCP/IP、UDP协议的区别,HTTP通讯协议的理解
    机器学习 笔记05——特征工程之特征处理:字典特征提取、文本特征提取
  • 原文地址:https://blog.csdn.net/qq_44981526/article/details/126322620