十三,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]python0045_四种进制_binary_octal_decimal_hexadecimal

    四种进制 回忆上次内容 上次研究了 通过 八进制数值 转义 \ooo 把(ooo)8进制对应的ascii字符输出 转义序列 \n.\t 是 转义序列 \xhh 也是 转义序列 \ooo 还是 转义序列 ...

  2. Python爬虫(5-10)-编解码、ajax的get请求、ajax的post请求、URLError/HTTPError、微博的cookie登录、Handler处理器

    五.编解码(Unicode编码) (1)GET请求 所提方法都在urllib.parse.路径下 get请求的quote()方法(适用于只提交一两个参数值) url='http://www.baidu ...

  3. MySQL 递归查询实践总结

    MySQL复杂查询使用实例 By:授客 QQ:1033553122   表结构设计 SELECT id, `name`, parent_id FROM `tb_testcase_suite` 说明: ...

  4. docker 容器迁移到其他机器

    docker 容器迁移到其他机器思路为:容器转为镜像,再保存为镜像文件,迁移到其他机器后导入为镜像 1.commit:将容器转镜像 # docker commit {container_id} {镜像 ...

  5. SpringTask

    SpringTask是spring提供的一个任务调度工具,按照约定的时间自动执行代码逻辑 定时任务框架,即定时自动执行某段代码 应用场景:信用卡每月还款提醒,火车售票系统处理未支付订单 cron表达式 ...

  6. 【SpringCloud】Nacos集群部署(Centos平台)

    一.前提环境准备 Nacos 下载 https://github.com/alibaba/nacos/releases 或者使用其它博主备份的 https://blog.csdn.net/weixin ...

  7. 【Vue】Re17 Router 第四部分(参数传递,守卫函数)

    一.案例搭建 新建Profile组件 组件写好内容后配置路由 { path : '/profile', component : () => import('../components/Profi ...

  8. 【PostgreSQL】01 环境搭建

    [PostgreSQL数据库安装] 数据库本体就没下本机了,直接挂服务器的Docker上面跑 docker pull postgres:9.4 创建容器并运行: docker run --name p ...

  9. ubuntu22.04 终端显示数字剑雨

    数字剑雨是读大学时候常用的屏保,这些年基本也再没有用过,不经意间想到了这个曾经的屏保,发现Ubuntu原版的桌面系统是没有屏保的,又不想换桌面系统,想想还是单独安装一下这个数字剑雨吧. 在Ubuntu ...

  10. Chrome(Google) 浏览器安装Vue2、Vue3插件方法 (亲测有效)

    1.背景 2.步骤 步骤一:下载插件 网站:https://chrome.zzzmh.cn/#/search 百度网盘下载: 链接:https://pan.baidu.com/s/1xdEK-7qVx ...