十三,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. Vue3 之 computed 计算属性的使用与源码分析详细注释

    目录 计算属性的基本用法 计算属性的源码 shared 工具方法抽离 计算属性的基本用法 computed 一般有两种常见的用法: 一:传入一个对象,内部有 set 和 get 方法,属于Comput ...

  2. Stopwatch 类来测量时间间隔

    使用 Stopwatch 类来测量时间间隔. 以下是一个示例代码,展示如何记录 Excel 导入的用时: ' 创建 Stopwatch 实例 Dim stopwatch As New Stopwatc ...

  3. 面试题-python 什么是闭包(closure)?

    前言 前面学了装饰器,那么闭包和装饰器有什么区别呢?闭包传递的是变量,而装饰器传递的是函数对象,只是传的参数内容不一样,闭包的概念包含了装饰器,可以说装饰器是闭包的一种,它只是传递函数对象的闭包. 先 ...

  4. c++ 快速复习第一部份

    去年有事无事学过一c++ ,,由于工作用不上,学来没有用,所以学得乱七八的,最近需要复习一下,因为最近想学习一下硬 件相关 第一   引用头文件和自定义头 #include <iostream& ...

  5. 简单写写IO流里的一些高级流

    缓冲流Buffered:缓冲流是一种高级的流,他可以对file类的流进行包装,内部含有一种缓冲池,可以在一定程度上提高IO的读写效率 不过,按实验来看,只要给低级流和缓冲流相似的byte读写,其实两者 ...

  6. SEO自动外链蜘蛛池工具促进百度快速收录怎么样 跟大家详谈一下

    此工具集成市面上所有自动外链网站的资源链接,经过合并.去重.筛选.验证 总结出最终的外链资源 ,软件实时更新 本软件将您繁杂的外链推广转为自动化进行,并且加入站群的支持,您只需要将你的站群域名粘贴到软 ...

  7. 【Windows】解决微软商店打不开的问题

    参考贴吧的帖子: https://tieba.baidu.com/p/6028738660#123983609458l 1.打开"运行"输入 inetcpl.cpl (" ...

  8. 【Scala】02 循环

    1.支持集合直接作为循环体的条件: // - - - - 支持集合遍历 - - - - var arr = Array(10, 20, 30) var arr2 = List(10, 20, 30) ...

  9. 暑假自学Java进度总结04

    一.今日所学: 1.下载并使用idea开发工具 1>了解idea的发展历史 2>尝试用idea编写代码 3>学习idea中的项目和模块操作 2.学习赋值运算符 加后赋值:" ...

  10. 运维 + AI,你得先搞懂这些

    很感谢夜莺提供如此优质的平台能和行业内顶尖技术大佬做面对面的交流,在这个会议中又学习到了很多有趣有深度的内容,给我在未来探索的道路上提供了一些新的指引方向.同时感谢夜莺社区的邀请,在此再做一次关于AI ...