十三,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. django 如何查询汇总的求和时避免没有数据导致的错误

    django 如何查询汇总的求和时避免没有数据导致的错误 在 Django 中,如果你希望对某个字段进行求和操作,并在没有数据时返回默认值,可以使用 aggregate 结合 Coalesce 函数. ...

  2. TIER 1: Sequel

    TIER 1: Sequel MySQL MySQL 是一种流行的开源关系型数据库管理系统(RDBMS),它被广泛用于存储和管理大量的结构化数据.MySQL 是由瑞典公司 MySQL AB 开发的,后 ...

  3. git 提交备注规范

    git 提交规范commit message = subject + :+ 空格 + message 主体 例如:feat:增加用户注册功能 常见的 subject 种类以及含义如下: feat: 新 ...

  4. 小技巧:初始化后查看容器内某一bean的信息

    1.debug 2. 3.与容器名对应,可以看到容器的对应信息 4.输入表达式可以直接获取对应结果信息,这里查看的是默认SpringSecurity过滤链的bean

  5. mybatis-plus的BaseMapper调用报错:Invalid bound statement

    1.yml的配置, 2.@mapper/@mapperScan 3.注意版本依赖冲突,本人第一次使用spring-boot-start-parent3.2.3与mybatis-plus-start-p ...

  6. appium python 点击坐标 tap

    appium python 点击坐标 tap 有时候定位元素的时候,你使出了十八班武艺还是定位不到,怎么办呢?(面试经常会问)那就拿出绝招:点元素所在位置的坐标 tap用法 1.tap是模拟手指点击, ...

  7. sql语句排序无效的问题

    数据可视化时因为数据类型排序无效的问题:这是由于你要排序的类型是String类型的而ORDER BY 方法排序要求整数型. 这就需要在ORDER BY 后加 CAST(需要排序的字段 AS UNSIG ...

  8. Jmeter函数助手28-urldecode

    urldecode函数用于解码application/x-www-form-urlencoded字符串. String to encode in URL encoded chars:填入applica ...

  9. 【SQL】 去掉最后一段,只保留前段

    需求描述: 例如给出这样一个地址或者其他字符: 10.11.12.13 192.168.177.209101.102.103.104.105 ... 要求只保留前面的部分,去掉最后一部分 10.11. ...

  10. 【Java】【常用类】SimpleDateFormat 简单日期格式化类

    Date类的API不易于国际化,大部分基本摈弃了 java.text.SimpleDateFormate 不和语言环境有关的方式来格式化和解析日期的具体类 支持 文本转格式,格式转文本 public ...