十三,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. 最后:

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

十三,Spring Boot 中注入 Servlet,Filter,Listener的更多相关文章

  1. day11-SpringBoot中注入Servlet&Filter&Listener

    SpringBoot中注入Servlet&Filter&Listener 1.基本介绍 文档:SpringBoot中注入Servlet&Filter&Listener ...

  2. Spring boot中使用servlet filter

    Spring boot中使用servlet filter liuyuhang原创,未经允许请勿转载! 在web项目中经常需要一些场景,如参数过滤防止sql注入,防止页面攻击,空参数矫正等, 也可以做成 ...

  3. spring boot中使用servlet、listener和filter

    spring boot中支持使用java Web三大组件(servlet.listener和filter),但是坑比较多,主要是spring boot内嵌tomcat和独立tomcat服务器有一些细节 ...

  4. 从零开始的Spring Boot(2、在Spring Boot中整合Servlet、Filter、Listener的方式)

    在Spring Boot中整合Servlet.Filter.Listener的方式 写在前面 从零开始的Spring Boot(1.搭建一个Spring Boot项目Hello World):http ...

  5. Spring Boot中使用Servlet与Filter

    在Spring Boot中使用Servlet,根据Servlet注册方式的不同,有两种使用方式.若使用的是Servlet3.0+版本,则两种方式均可使用:若使用的是Servlet2.5版本,则只能使用 ...

  6. Spring boot中注册Servlet

    Spring boot中注册Servlet 如何在spring boot项目中注册Servlet呢? 如何在spring boot项目中注册Servlet呢? 由于没有web.xml,无法直接在xml ...

  7. SpringBoot学习笔记(6)----SpringBoot中使用Servlet,Filter,Listener的三种方式

    在一般的运用开发中Controller已经大部分都能够实现了,但是也不排除需要自己实现Servlet,Filter,Listener的方式,SpringBoot提供了三种实现方式. 1. 使用Bean ...

  8. Spring Boot2 系列教程(十三)Spring Boot 中的全局异常处理

    在 Spring Boot 项目中 ,异常统一处理,可以使用 Spring 中 @ControllerAdvice 来统一处理,也可以自己来定义异常处理方案.Spring Boot 中,对异常的处理有 ...

  9. Spring Boot 2 使用Servlet、Listener和Filter配置

    开发环境:IntelliJ IDEA 2019.2.2Spring Boot版本:2.1.8 新建一个名称为demo的Spring Boot项目. 一.使用Servlet配置 1.修改启动类 Demo ...

  10. Spring Boot中注入配置文件application.properties中的list 对象参数

    例如要注入下列参数: dyn.spring.datasources[0].name=branchtadyn.spring.datasources[0].driverClassName=oracle.j ...

随机推荐

  1. [oeasy]python0008_输出h字符_REPL_引号_括号_什么是函数

    输出h字符_REPL_引号_括号_什么是函数 回忆上次内容 上次 继续在游乐场里 玩耍 键盘按键 作用 ↑ 上一条指令 ↓ 下一条指令 ← 光标 向左移动 一格 → 光标 向右移动 一格 ctrl + ...

  2. 【VMware VCF】VMware Cloud Foundation Part 01:概述。

    VMware Cloud Foundation(简称 VCF)是 VMware 打造的一套用于 Software Defined Data Center(SDDC)软件定义数据中心的全栈云平台解决方案 ...

  3. Web 开发技术栈

    Web 开发技术栈 Web 是什么? 简单地说,网络是一个遍布全球的网络,它连接大量设备并允许它们相互通信 Internet 上的网站托管在称为服务器的设备上,当与 Internet 上的网页交互时, ...

  4. Django 实现文件上传下载API

    Django 实现文件上传下载API by:授客 QQ:1033553122 欢迎加入全国软件测试交流QQ群7156436 开发环境   Win 10   Python 3.5.4   Django- ...

  5. vue 拖拉改变盒子高度(mousedown、mousemove、mouseup)流畅不卡顿

    需求:上下两个盒子之间添加可拖拽按钮,实现高度变化 html: <textarea :id="'mycode'+(index*1+1)" :ref="'mycode ...

  6. java面试一日一题:java内存模型

    问题:请讲下java内存模型? 分析:该问题比较容易和jvm内存区域(java内存结构)这样的问题混淆,其实他们是两个概念,jvm内存区域指的是运行时的几块数据区域,包括堆.方法区.虚拟机栈.本地方法 ...

  7. Redis持久化RDB与AOF介绍

    就是将内存中的数据通过rdb/aof进行持久化写入硬盘中 rdb就是进行持久化的快照 在指定的时间间隔内,执行数据集的时间点快照.这个快照文件称为(dump.rdb)RDB文件,Redis DataB ...

  8. mybatisplus关于驼峰命名法与下划线的映射

    今天遇到一个很坑的事情,我在测试之前的案例的时候我有一个字段的名字是typeId,我调试之后发现插入出现了错误. 开启sql日志之后我发现mybatisplus自动把我的typeId改成type_id ...

  9. 低代码如何借助 K8s 实现高并发支持?

    引言 在当今这个数字化时代,互联网的普及和技术的飞速发展使得应用程序面临着前所未有的挑战,其中最为显著的就是高并发访问的需求.随着用户数量的激增和业务规模的扩大,如何确保应用在高并发场景下依然能够稳定 ...

  10. 【Linux】Re02

    一.运行启动级别 0 关机 1 单用户 2 多用户状态没有网络服务 3 多用户状态存在网络服务 4 系统未使用保留给用户 5 图形界面 6 重启 命令: init [0 - 6] 图形化界面级别需要对 ...