SpringBoot中注入ServletFilterListener

1.基本介绍

文档:SpringBoot中注入Servlet&Filter&Listener

  1. 考虑到实际开发业务非常复杂和兼容问题,SpringBoot支持将Servlet、Filter、Listener注入spring容器中,成为Spring Bean
  2. 也就是说,SpringBoot开放了和原生WEB组件(Servlet、Filter、Listener)的兼容
  3. SpringBoot注入Servlet、Filter、Listener,有两种方式:
    • 通过注解方式注入
    • 使用RegistrationBean方式注入

2.通过注解方式注入

2.1@WebServlet

属性名对应标签描述
name<servlet-name>指定 Servlet 的 name 属性。 如果没有显式指定,则取值为该 Servlet 的完全限定名,即包名+类名
value<url-pattern>该属性等价于 urlPatterns 属性,两者不能同时指定。 如果同时指定,通常是忽略 value 的取值
urlPatterns<url-pattern>指定一组 Servlet 的 URL 匹配模式
loadOnStartup<load-on-startup>指定 Servlet 的加载顺序
initParams<init-param>指定一组 Servlet 初始化参数
asyncSupported<async-supported>声明 Servlet 是否支持异步操作模式
description<description>指定该 Servlet 的描述信息
displayName<display-name>指定该 Servlet 的显示名

例子--使用@WebServlet注入Servlet

(1)MyServlet.java

  1. 通过继承HttpServlet来开发原生的Servlet

  2. 使用@WebServlet,表示将其标识的对象注入到Spring容器中

  3. urlPatterns = {"servlet01","servlet02"} 对此servlet配置了映射路径

  4. 对于开发的原生的Servlet,需要使用@ServletComponentScan在SpringBoot主程序中,指定要扫描的原生Servlet,这样该Servlet才能注入容器

 
package com.li.thymeleaf.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;
/**
* @author 李
* @version 1.0
*/
@WebServlet(urlPatterns = {"/servlet01", "/servlet02"})
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello,MyServlet!");
}
}

(2)Application.java主程序

 
package com.li.thymeleaf;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
/**
* @author 李
* @version 1.0
*/
//指定扫描Servlet
@ServletComponentScan(basePackages = "com.li.thymeleaf")
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}

(3)浏览器访问地址:http://localhost:8080/servlet01获者http://localhost:8080/servlet02,返回如下:

注意:注入的Servlet不会被SpringBoot的拦截器拦截(因为原生Servlet和前端控制器DispatcherServlet是统一级别的,而拦截器在DispatcherServlet中)

2.2@WebFilter

属性名说 明
description该过滤器的描述信息,等价于 <description>标签。
displayName该过滤器的显示名,通常配合工具使用,等价于 <display-name> 标签
initParams指定一组过滤器初始化参数,等价于 <init-param> 标签。
filterName指定过滤器的 name 属性,等价于 <filter-name>
servletNames指定过滤器将应用于哪些 Servlet。取值是 @WebServlet 中的 name 属性的取值,或者是 web.xml 中 <servlet-name> 的取值
value/urlPatterns过滤器的 URL 匹配模式,等价于<url-pattern>标签
dispatcherTypes指定过滤器的转发模式。具体取值包括: ASYNC、ERROR、FORWARD、INCLUDE、REQUEST。
asyncSupported声明过滤器是否支持异步操作模式, 等价于<async-supported>标签

例子--使用@WebFilter注入Filter

  1. @WebFilter标识一个过滤器,并注入spring容器

  2. urlPatterns = {"/css/*", "/images/*"}表示请求/css/目录或者/images/目录下的资源时,请求会经过这个过滤器

  3. 需要在主程序中,指定要扫描的Filter,这样该Filter才能注入容器

 
package com.li.thymeleaf.filter;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author 李
* @version 1.0
* 开发Filter并注入spring容器
*/
@Slf4j
@WebFilter(urlPatterns = {"/css/*", "/images/*"})
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("MyFilter的init()方法被执行...");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
log.info("MyFilter的doFilter()方法被执行...");
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
log.info("过滤器处理的uri={}", httpServletRequest.getRequestURI());
chain.doFilter(request, response);//放行
}
@Override
public void destroy() {
log.info("MyFilter的destroy()方法被执行...");
}
}

(2)在主程序中配置扫描该过滤器(略)

(3)在浏览器访问地址:http://localhost:8080/images/login.jpg,后台输出:

 
2023-03-23 18:59:36.685 INFO 39228 --- [nio-8080-exec-6] com.li.thymeleaf.filter.MyFilter : MyFilter的doFilter()方法被执行...
2023-03-23 18:59:36.685 INFO 39228 --- [nio-8080-exec-6] com.li.thymeleaf.filter.MyFilter : 过滤器处理的uri=/images/login.jpg

有时候后台没有输出,可能是浏览器缓存问题

2.3@WebListener

(1)MyListener.java

 
package com.li.thymeleaf.listener;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
/**
* @author 李
* @version 1.0
*/
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
//可以加入项目初始化相关的业务
log.info("MyListener-contextInitialized()-项目初始化OK~");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
//可以加入业务
log.info("MyListener-contextDestroyed()-项目初销毁...");
}
}

(2)在主程序 Application.java配置扫描该监听器

 
package com.li.thymeleaf;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;
/**
* @author 李
* @version 1.0
*/
//指定扫描监听器
@ServletComponentScan(basePackages = "com.li.thymeleaf")
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext ioc =
SpringApplication.run(Application.class, args);
//监听器的contextDestroyed()方法在容器销毁时触发
ioc.stop();
}
}

(3)启动项目,控制台输出:

3.使用RegistrationBean方式注入

RegistrationConfig.java:

 
package com.li.thymeleaf.config;
import com.li.thymeleaf.filter.MyFilter;
import com.li.thymeleaf.listener.MyListener;
import com.li.thymeleaf.servlet.MyServlet;
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;
/**
* @author 李
* @version 1.0
* RegistrationConfig是一个配置类,
* 默认为单实例模式 proxyBeanMethods=true
*/
@Configuration
public class RegistrationConfig {
//使用RegistrationBean方式注入Servlet
@Bean
public ServletRegistrationBean servlet_() {
MyServlet myServlet = new MyServlet();
//将myServlet关联到ServletRegistrationBean对象
//可以指定多个映射url
return new ServletRegistrationBean(myServlet, "/servlet01", "/servlet02");
}
//使用RegistrationBean方式注入Filter
@Bean
public FilterRegistrationBean filter_() {
MyFilter myFilter = new MyFilter();//创建原生的Filter对象
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
//设置filter的urlPattern
filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*", "/images/*"));
return filterRegistrationBean;
}
//使用RegistrationBean方式注入Listener
@Bean
public ServletListenerRegistrationBean listener_() {
MyListener myListener = new MyListener();//创建原生的Listener对象
return new ServletListenerRegistrationBean(myListener);
}
}

使用RegistrationBean的方式注入,不必在主程序Application.java中配置扫描

运行程序,可以看到三个组件都被注入到容器中:

4.注意事项和细节

4.1请求自定义Servlet时,为什么不会到达拦截器?

原因分析:

注入的Servlet会存在Spring容器,DispatcherServlet也存在Spring容器。当多个Servlet都能处理到同一层路径时,存在精确优先原则/最长前缀匹配原则:**精准匹配 > 目录匹配 > 扩展名匹配 > /* > / **

如下图:当浏览器请求路径为/servlet01时,MyServlet的映射路径对与浏览器请求来说是精准匹配,因此此时MyServlet的映射路径优先级高于前端控制器的 /,请求路径会走tomcat流程,不会到达前端控制器,也就不会执行拦截器。

当然,在SpringBoot中,去调用@Controller目标方法,仍是按照DispatcherServlet分发匹配的机制

4.2DispatcherServlet在SpringBoot如何进行配置和注入

DispatcherServletAutoConfiguration 完成对 DispatcherServlet 的自动配置。

DispatcherServletAutoConfiguration 类,有一个内部类:

 
@Configuration(proxyBeanMethods = false)
@Conditional(DefaultDispatcherServletCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
protected static class DispatcherServletConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
//创建了DispatcherServlet对象,并进行一系列设置并返回。
public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
return dispatcherServlet;
}
@Bean
@ConditionalOnBean(MultipartResolver.class)
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
public MultipartResolver multipartResolver(MultipartResolver resolver) {
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
}

然后通过如下方法,创建DispatcherServletRegistrationBean对象,并将创建的DispatcherServlet对象关联到这个DispatcherServletRegistrationBean对象中,将DispatcherServletRegistrationBean对象通过@Bean注入到容器中。

 
@Configuration(proxyBeanMethods = false)
@Conditional(DispatcherServletRegistrationCondition.class)
@ConditionalOnClass(ServletRegistration.class)
@EnableConfigurationProperties(WebMvcProperties.class)
@Import(DispatcherServletConfiguration.class)
protected static class DispatcherServletRegistrationConfiguration {
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
webMvcProperties.getServlet().getPath());//设置路径 /
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
multipartConfig.ifAvailable(registration::setMultipartConfig);
return registration;
}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/904.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于单片机智能洗衣机设计与实现

功能介绍 以51单片机作为主控系统&#xff1b;利用STC89C52单片机进行数据处理&#xff1b; 通过2路继电器分别控制洗衣机进水、出水相关逻辑运算&#xff1b;采用L298去掉直流电机实现滚筒正反转&#xff1b;通过单片机进行处理数据&#xff0c;把采集到的数据通过LCD液晶显示…

基于Nonconvex规划的配电网重构研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

网络安全与密码学

1、网络安全威胁 破坏网络安全的一些理论方式&#xff1a; 窃听&#xff1a;窃听信息&#xff0c;在网路通信双方直接进行窃听。 插入&#xff1a;主动在网络连接中插入信息&#xff08;可以在message中插入恶意信息&#xff09; 假冒&#xff1a;伪造&#xff08;spoof&#x…

SQLServer2022安装(Windows),已验证

二、安装可视化工具SSMS 接下来安装可视化工具SSMS&#xff0c;现在新版本默认都是没有可视化界面&#xff0c;需要单独安装 &#xff08;1&#xff09;地址&#xff1a;下载 SQL Server Management Studio (SSMS) - SQL Server Management Studio (SSMS) | Microsoft Learn…

LayUI之CRUD(增删改查)

目录 一、前期准备 1.数据表格 2.弹出层 3.用户表数据查询 二、用户管理后台编写 三、前端JS编写 四、效果展示 一、前期准备 1.数据表格 在layui官网找到我们需要的数据表格 根据需求复制修改代码&#xff0c;再找到表单复制一个输入框和按钮&#xff0c;做一个搜索功能…

语言模型的自洽性思维链推理技术

论文标题&#xff1a;Self-Consistency Improves Chain of Thought Reasoning in Language Models 论文链接&#xff1a;https://arxiv.org/abs/2203.11171 论文来源&#xff1a;ICLR 2023 一、概述 尽管语言模型在一系列NLP任务中展现出了显著的成功&#xff0c;但它们在推理能…

进制转换详解(解释原理简单易懂)

前言&#xff1a;在网上看了许多篇关于不同进制之间如何转换的文章&#xff0c;包括很多浏览量上万的博客。大多都只是把转换的规则罗列了出来&#xff0c;例如十进制转二进制&#xff0c;可能大家都知道方法&#xff0c;“除以2反向取余数&#xff0c;直到商为0”。应用该方法…

Kubespray v2.22.1 在线部署 kubernetes v1.26.5 集群

文章目录 1. 介绍2. 预备条件3. 配置 hostname4. yum5. 下载介质5.1 git 下载5.2 下载 kubespray v2.22.1 6. 编写 inventory.ini7. 配置互信8. 安装 ansible9. 关闭防火墙10. 安装 docker11. 配置内核参数12. 启动容器 kubespray13. 部署14. 配置连接集群 1. 介绍 kubespray​…

论文阅读—2023.7.13:遥感图像语义分割空间全局上下文信息网络(主要为unet网络以及改unet)附加个人理解与代码解析

前期看的文章大部分都是深度学习原理含量多一点&#xff0c;一直在纠结怎么改模型&#xff0c;论文看的很吃力&#xff0c;看一篇忘一篇&#xff0c;总感觉摸不到方向。想到自己是遥感专业&#xff0c;所以还是回归遥感影像去谈深度学习&#xff0c;回归问题&#xff0c;再想着…

5月更新,docsify综合漏洞知识库!

项目介绍 一个知识库&#xff0c;集成了Vulhub、Peiqi、EdgeSecurity、0sec、Wooyun等开源漏洞库&#xff0c;涵盖OA、CMS、开发框架、网络设备、开发语言、操作系统、Web应用、Web服务器、应用服务器等多种漏洞。 关注【Hack分享吧】公众号&#xff0c;回复关键字【230428】获…

spring boot security自定义认证

前言 前置阅读 spring boot security快速使用示例 spring boot security之前后端分离配置 说明 实际场景&#xff0c;我们一般是把用户信息保存在db中&#xff08;也可能是调用三方接口&#xff09;&#xff0c;需要自定义用户信息加载或认证部分的逻辑&#xff0c;下面提供…

bug:file name too long文件名超出系统最大限制

各操作系统支持最长的文件和目录名称长度&#xff08;Linux、Win、Mac&#xff09; 今天开发需求的时候发现无法新建文件&#xff0c;提示file name too lang&#xff0c;于是翻阅和查询了一些资料&#xff0c;发现不同操作系统下文件名和目录名最长的长度不同。 操作系统文件名…

小程序主包超1.5MB分包处理流程优化方案

"subPackages": [// 分包1 {"root": "src, // 根目录"pages": [{"path": "views/business/index", // 页面路径"name": "business_index","aliasPath": "/business/index",&…

make/makefile的使用

make/makefile 文章目录 make/makefile初步认识makefile的工作流程依赖关系和依赖方法make的使用 总结 make是一个命令&#xff0c;是一个解释makefile中指令的命令工具&#xff0c;makefile是一个文件&#xff0c;当前目录下的文件&#xff0c;两者搭配使用&#xff0c;完成项…

Python采集课堂视频教程, m3u8视频解密

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 环境使用: Python 3.8 解释器 Pycharm 编辑器 模块使用&#xff1a; requests >>> pip install requests pycryptodome --> pip install pycryptodome re 第三方模块安装方法&#xff1a; win R 输…

7.14~7.15学习总结

Java的前置知识学习时间截至了&#xff0c;慌的一批~~。 看看自己学的&#xff0c;再看看要求学的&#xff0c;简直&#xff1a; 现在继续&#xff1a;IO流里面的Commons_IO的用法&#xff1a; public class Main {public static void main(String[]args) throws IOException…

【C++】多线程编程三(std::mutexstd::mutex、std::lock_guard、std::unique_lock详解)

目录 一、线程间共享数据 1.数据共享和条件竞争 2.避免恶性条件竞争 二、用互斥量来保护共享数据 1. 互斥量机制 2.mutex头文件介绍 三、C中使用互斥量mutex 1. 互斥量mutex使用 2.mutex类成员函数 ① 构造函数 ② lock() ③ unlock() ④ try_lock() 四、使用std::…

如何与ChatGPT愉快地聊天

原文链接&#xff1a;https://mp.weixin.qq.com/s/ui-O4CnT_W51_zqW4krtcQ 人工智能的发展已经走到了一个新的阶段&#xff0c;在这个阶段&#xff0c;人工智能可以像人一样与我们进行深度的文本交互。其中&#xff0c;OpenAI的ChatGPT是一个具有代表性的模型。然而&#xff0…

mac安装Golang开发环境及快速入门

目录 一、Mac brew 安装go环境 1.1 安装步骤 1.2 设置GOPATH 及环境变量 1.3 编写第一个go程序 二、快速入门 2.1 快速入门需求 2.2 go学习&#xff08;自用&#xff09; 2.2.1 go基础程序 2.2.2 变量声明 2.2.3 常量和枚举 2.2.4 函数与多种返回值 2.2.5 init函数…

18.Lucas-Kanade光流及OpenCV中的calcOpticalFlowPyrLK

文章目录 光流法介绍OpenCV中calcOpticalFlowPyrLK函数补充reference 欢迎访问个人网络日志&#x1f339;&#x1f339;知行空间&#x1f339;&#x1f339; 光流法介绍 光流描述了像素在图像中的运动&#xff0c;就像彗星☄划过天空中流动图像。同一个像素&#xff0c;随着时…