首页 星云 工具 资源 星选 资讯 热门工具
:

PDF转图片 完全免费 小红书视频下载 无水印 抖音视频下载 无水印 数字星空

十三,Spring Boot 中注入 Servlet,Filter,Listener

编程知识
2024年09月15日 15:27

十三,Spring Boot 中注入 Servlet,Filter,Listener

@

目录


1. 基本介绍

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

在Spring Boot 当中对应 Servlet,Filter (过滤器),Listener(监听器)的注入,有两种方式:

  • 第一种方式:使用注解方式注入 。
  • 第二种方式:使用 RegistrationBean方式注入 Servlet,Filter,Listener 的方式注入。

2. 第一种方式:使用注解方式注入:Servlet,Filter,Listener

2.1 使用注解方式注入:Servlet

使用(@WebServlet + @ServletComponentScan ) 这两个注解方式注入 Servlet

提示: urlPatterns = {"/servlet01","servlet02"},对Servlet配置了url-pat:请求路径的映射

  • 注入的原生的 Servlet_,不会被Spring boot的拦截器拦截
  • 对于开发的原生的Servlet,需要使用@ServletComponentScan指定要扫描的原生Servlet,才会注入到 Spring容器当中,注意:是在启动场景的位置添加该@ServletComponentScan注解。

在这里插入图片描述

package com.rainbowsea.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;


// 使用 extends 继承的方式(@WebServlet + @ServletComponentScan 注解),注入 servlet
@WebServlet(urlPatterns = {"/servlet01","/servlet02"}) // 注意是: / 开头
public class Servlet_ extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response
    ) throws ServletException,
            IOException {
        // 在前端显示打印显示一些信息。
        response.getWriter().write("hello , Servlet_!");

    }
}

注意需要在对应项目的场景启动器的位置,使用@ServletComponentScan 注解,在该注解的 basePackages 属性指明要让 Spring Boot扫描到的包的路径。让 Spring Boot可以找到你想让它注入的 ioc 容器当中的类。

在这里插入图片描述

package com.rainbowsea.springboot;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;


@SpringBootApplication // 项目启动标志
@ServletComponentScan(basePackages = {"com.rainbowsea.springboot"})
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext ioc = SpringApplication.run(Application.class, args);
        //ioc.stop();  // 停止容器

        System.out.println("hello");
    }
}

运行测试:

在这里插入图片描述

2.2 使用注解方式注入:Filter

使用(@WebFilter+ @ServletComponentScan ) 这两个注解方式注入 Filter

注意注入的 Filter 过滤器要实现 implements javax.servlet.Filter 下的 Filter

/ 注意是:  javax.servlet.Filter 下的 Filter
// 注入过滤器:(使用: @WebFilter(urlPatterns = {"/css/*","/images/*"}) + @ServletComponentScan(basePackages = {"com.rainbowsea.springboot"}))
/*
@WebFilter(urlPatterns = {"/css/*", "/images/*"})
@WebFilter 表示 Filter_是一个过滤器,并注入容器
urlPatterns = {"/css/*", "/images/*"} 当请求 /css/ 目录资源或者images
解读: 直接放行后,在经过拦截器,拦截器是否拦截要根据拦截器的拦截规则

特别说明在:之前下面这样配置的拦截器也是会拦截内容的。
 @Bean
    public WebMvcConfigurer webMvcConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                System.out.println("addInterceptors~~~");
                // 注册拦截器
                registry.addInterceptor(new LoginInterceptor())
                        .addPathPatterns("/**")
                        .excludePathPatterns("/","/login","/images/**");
            }
        };
    }

注意:过滤器配置的urlPatterns 也会经过 Spring-Boot拦截器,所以为了
看到效果,请在拦截器配置放行 /css/**,
在 servlet 表示全部匹配是 "/*";而在 Spring boot 中表示全部匹配的是: "/**"

在这里插入图片描述

package com.rainbowsea.springboot.servlet;


import lombok.extern.slf4j.Slf4j;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;



@Slf4j
@WebFilter(urlPatterns = {"/static/css/*", "/images/*"})  // 注意:是/开头
public class Filter_ implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("--Filter_ init0--");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("Filter - doFitler");
        // 为了方便观察过滤器处理的资源,我们输出一个url
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        log.info("过滤器处理的 url={}",httpServletRequest.getRequestURI());

        // 我们直接放行,实际开发中,根据自己的业务来决定如何处理
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        log.info("Filter -destory");
    }
}

同样注意:需要在对应项目的场景启动器的位置,使用@ServletComponentScan 注解,在该注解的 basePackages 属性指明要让 Spring Boot扫描到的包的路径。让 Spring Boot可以找到你想让它注入的 ioc 容器当中的类。

在这里插入图片描述

运行测试:

在这里插入图片描述

2.3 使用注解方式注入:Listener

使用(@WebListener+ @ServletComponentScan ) 这两个注解方式注入 Servlet

在这里插入图片描述

package com.rainbowsea.springboot.servlet;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

// 注入监听器(@WebListener + @ServletComponentScan(basePackages = {"com.rainbowsea.springboot"}))
@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_ contextInitialized 项目销毁OK~");
    }
}

同样注意:需要在对应项目的场景启动器的位置,使用@ServletComponentScan 注解,在该注解的 basePackages 属性指明要让 Spring Boot扫描到的包的路径。让 Spring Boot可以找到你想让它注入的 ioc 容器当中的类。

在这里插入图片描述

运行测试:

在这里插入图片描述

在这里插入图片描述

3. 第二种方式:使用 RegistrationBean 方式注入 Servlet,Filter,Listener

3.1 使用 RegistrationBean 方式注入 Servlet

在这里插入图片描述

package com.rainbowsea.springboot.config;


import com.rainbowsea.springboot.servlet.Filter_;
import com.rainbowsea.springboot.servlet.Listener_;
import com.rainbowsea.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;

// 使用  配置类的方式注入,servlet,和 Listener监听器,filter过滤器

/*
 * @Configuration(proxyBeanMethods = true)
 * @Configuration 表示是一个配置类
 * proxyBeanMethods = true 默认是单例返回 bean(保证每个 @bean 方法被调用多少次,都是同一个)

*/
@Configuration(proxyBeanMethods = true)
public class RegisterConfig_ {


    // 以使用RegistrationBean 方式
    // 注入 Servlet
    // 注意:要加上 Bean 对象
    //@Bean(name = "Servlet_") // bean 没有指明name的话,默认是以方法名作为 name/id
    @Bean
    public ServletRegistrationBean servlet2() {
        // 创建原生的 Servlet 对象(就是我们自己创建的 Servlet)
        Servlet_ servlet_ = new Servlet_();

        // 把 Servlet_ 对象 关联到 ServletRegistrationBean 对象
        // "/servlet03" 就是注入Servlet的url-pattern
        return new ServletRegistrationBean(servlet_, "/servlet03");
    }

}

package com.rainbowsea.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;



public class Servlet_ extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response
    ) throws ServletException,
            IOException {
        // 在前端显示打印显示一些信息。
        response.getWriter().write("hello , Servlet_!");

    }
}

注意需要在对应项目的场景启动器的位置,使用@ServletComponentScan 注解,在该注解的 basePackages 属性指明要让 Spring Boot扫描到的包的路径。让 Spring Boot可以找到你想让它注入的 ioc 容器当中的类。

在这里插入图片描述

package com.rainbowsea.springboot;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;


@SpringBootApplication // 项目启动标志
@ServletComponentScan(basePackages = {"com.rainbowsea.springboot"})
public class Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext ioc = SpringApplication.run(Application.class, args);
        //ioc.stop();  // 停止容器

        System.out.println("hello");
    }
}

运行测试:

在这里插入图片描述

3.2 使用 RegistrationBean 方式注入 Filter

在这里插入图片描述

package com.rainbowsea.springboot.config;


import com.rainbowsea.springboot.servlet.Filter_;
import com.rainbowsea.springboot.servlet.Listener_;
import com.rainbowsea.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;

// 使用  配置类的方式注入,servlet,和 Listener监听器,filter过滤器

/*
 * @Configuration(proxyBeanMethods = true)
 * @Configuration 表示是一个配置类
 * proxyBeanMethods = true 默认是单例返回 bean(保证每个 @bean 方法被调用多少次,都是同一个)

*/
@Configuration(proxyBeanMethods = true)
public class RegisterConfig_ {


    // 注入 Filter
    // 注意:要加上 Bean 对象
    @Bean(name = "Filter_")
    public FilterRegistrationBean filter2() {
        // 创建原生的 Filter_ 对象(就是我们自己创建的 Filter_)
        Filter_ filter_ = new Filter_();
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(filter_);
        // 设置 filter 的 url-pattern
        // Arrays.asList("/css/*","images/*") 将字符串,转换为 集合
        // 注意:不要漏 "/" 开头了。
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*", "/images/*"));

        return filterRegistrationBean;
    }

 
}

package com.rainbowsea.springboot.servlet;


import lombok.extern.slf4j.Slf4j;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;


@Slf4j
public class Filter_ implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        log.info("--Filter_ init0--");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        log.info("Filter - doFitler");
        // 为了方便观察过滤器处理的资源,我们输出一个url
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        log.info("过滤器处理的 url={}",httpServletRequest.getRequestURI());

        // 我们直接放行,实际开发中,根据自己的业务来决定如何处理
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        log.info("Filter -destory");
    }
}

同样注意:需要在对应项目的场景启动器的位置,使用@ServletComponentScan 注解,在该注解的 basePackages 属性指明要让 Spring Boot扫描到的包的路径。让 Spring Boot可以找到你想让它注入的 ioc 容器当中的类。

在这里插入图片描述

运行测试:

在这里插入图片描述

3.3 使用 RegistrationBean 方式注入 Listener

在这里插入图片描述

package com.rainbowsea.springboot.config;


import com.rainbowsea.springboot.servlet.Filter_;
import com.rainbowsea.springboot.servlet.Listener_;
import com.rainbowsea.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;

// 使用  配置类的方式注入,servlet,和 Listener监听器,filter过滤器

/*
 * @Configuration(proxyBeanMethods = true)
 * @Configuration 表示是一个配置类
 * proxyBeanMethods = true 默认是单例返回 bean(保证每个 @bean 方法被调用多少次,都是同一个)

*/
@Configuration(proxyBeanMethods = true)
public class RegisterConfig_ {

    
    // 注入: Listener
    //@Bean(name = "Listener_")
    @Bean
    public ServletListenerRegistrationBean Listener2() {
// 创建原生的 Listener_ 对象(就是我们自己创建的 Listener_)
        Listener_ listener_ = new Listener_();

        return new ServletListenerRegistrationBean(listener_);

    }
}

package com.rainbowsea.springboot.servlet;

import lombok.extern.slf4j.Slf4j;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

// 注入监听器(@WebListener + @ServletComponentScan(basePackages = {"com.rainbowsea.springboot"}))
@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_ contextInitialized 项目销毁OK~");
    }
}

同样注意:需要在对应项目的场景启动器的位置,使用@ServletComponentScan 注解,在该注解的 basePackages 属性指明要让 Spring Boot扫描到的包的路径。让 Spring Boot可以找到你想让它注入的 ioc 容器当中的类。

在这里插入图片描述

运行测试:

在这里插入图片描述

在这里插入图片描述

4. 注意事项和细节说明

请求 (自己所编写的)Servlet 时,为什么不会到达拦截器

请求 Servlet 时,不会到达 DispatherServlet,因此也不会到达拦截器
原因分析:
注入的Servlet会存在Spring容器
DispatherServlet也存在Spring 容器
多个Servlet容器能处理到同一层拦截,精确优先原则/最长前缀匹配原则
所以当请求 /servlet01 时,就会直接匹配到注入的servlet
简单的说:就是当你 servlet之间跳转通信的时候,是先找同一层的servlet,如果你同一层的
servlet有你所需要的映射的请求路径,那么优先跳转到servlet上,而不走 拦截器了,因为拦截器是在介于 servlet 和 Controller 控制器之间的。
大家可以回忆一下:我们讲过的 Tomcat 在对 Servlet url 匹配的原则,多个servlet都能处理到同一层路径,精确优先原则/最长前缀匹配原则
在Spring Boot 中,去调用@Controller 目标方法,是按照 DispatherServlet 分发匹配的机制,请同学们回顾一下,我们自己实现Spring MVC 的底层机制的程序。

5. 总结:

  1. 第一种方式:使用注解方式注入Servlet,Filter,Listener:

    1. 使用(@WebServlet + @ServletComponentScan ) 这两个注解方式注入 Servlet
    2. 使用(@WebFilter+ @ServletComponentScan ) 这两个注解方式注入 Filter
    3. 使用(@WebListener+ @ServletComponentScan ) 这两个注解方式注入 Servlet
  2. 第二种方式:使用 RegistrationBean 方式注入 Servlet,Filter,Listener 。

  3. 注意:无论是第一种方式还是第二种方式,都必须在对应项目的场景启动器的位置上,使用上: @ServletComponentScan注解。在该注解的 basePackages 属性指明要让 Spring Boot扫描到的包的路径。让 Spring Boot可以找到你想让它注入的 ioc 容器当中的类。

    在这里插入图片描述

6. 最后:

“在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。”

在这里插入图片描述

From:https://www.cnblogs.com/TheMagicalRainbowSea/p/18415336
本文地址: http://www.shuzixingkong.net/article/2044
0评论
提交 加载更多评论
其他文章 MonoDevelop 的续集dotdevelop
DotDevelop 是一个跨平台的 .NET 集成开发环境(IDE),它原本是 MonoDevelop 的分支项目,这个项目更侧重于 Linux 支持和 GTK3 升级,github:https://github.com/dotdevelop/dotdevelop。MonoDevelop 是一个开
manim边学边做--弧形多边形
弧形多边形是一种结合了圆弧和多边形的图形,这类几何图形在设计中应用非常广泛。 比如在家居设计中,看看家里的沙发,餐桌和座椅等,它们的边角,靠背等地方都是弧形的设计,这种设计有效柔化了室内空间,使整体氛围更加和谐自然。 还有景观和建筑设计中,弧形多边形常被用于道路规划、花坛布局等, 特别是儿童游乐的区
manim边学边做--弧形多边形 manim边学边做--弧形多边形 manim边学边做--弧形多边形
MySQL 大表拆分
概述 在实际工作中,在关系数据库(MySQL、PostgreSQL)的单表数据量上亿后,往往会出现查询和分析变慢甚至无法执行统计分析的情况。这时就需要将大表拆分为多个小表,将小表分布在多个数据库上,形成一个数据库集群。这样的话,一条 SQL 统计语句就可以在多台服务器上并发执行,然后将执行结果汇总,
MySQL 大表拆分 MySQL 大表拆分 MySQL 大表拆分
这些年没来得及学习的一些 HTML5 标签
认识并学习下还没来得及学习的一些 HTML5 标签 <ruby> 标签 HTML <ruby> 元素被用来展示东亚文字注音或字符注释。 比如: <ruby>兄弟<rt>xiongdi</rt></ruby>
这些年没来得及学习的一些 HTML5 标签 这些年没来得及学习的一些 HTML5 标签 这些年没来得及学习的一些 HTML5 标签
计算机执行汇编代码的原理
计算机执行汇编代码的原理 汇编语言(Assembly Language)是一种低级编程语言,它与机器语言(Machine Language)密切相关。汇编语言由人类可读的指令构成,这些指令会被转化为机器可以理解的二进制代码,即机器码。本文将介绍计算机如何执行汇编代码的基本原理,并通过图文说明帮助理解
计算机执行汇编代码的原理 计算机执行汇编代码的原理 计算机执行汇编代码的原理
Qml 实现星级评分组件 已发布
在现代应用程序中,星级评分是一个常见的用户界面元素,它允许用户对产品、服务或内容进行评价。 想必大家在用各种带有评分的软件中看到过这个组件: 本文将指导你如何使用 Qml 创建一个简单而美观的星级评分组件,并且支持高度自定义。
Qml 实现星级评分组件  已发布 Qml 实现星级评分组件  已发布 Qml 实现星级评分组件  已发布
代码整洁之道--读书笔记(10)
代码整洁之道 简介: 本书是编程大师“Bob 大叔”40余年编程生涯的心得体会的总结,讲解要成为真正专业的程序员需要具备什么样的态度,需要遵循什么样的原则,需要采取什么样的行动。作者以自己以及身边的同事走过的弯路、犯过的错误为例,意在为后来者引路,助其职业生涯迈上更高台阶。 本书适合所有程序员阅读,
代码整洁之道--读书笔记(10) 代码整洁之道--读书笔记(10)
Go runtime 调度器精讲(七):案例分析
原创文章,欢迎转载,转载请注明出处,谢谢。 0. 前言 前面用了六讲介绍 Go runtime 调度器,这一讲我们看一个关于调度 goroutine 的程序案例分析下调度器做了什么。需要说明的是,这个程序和抢占有关,抢占目前为止还没有介绍到,如果看不懂也没有关系,有个印象就行。 1. 案例 1 执行