十三,Spring Boot 中注入 Servlet,Filter,Listener

cnblogs 2024-09-15 16:39:00 阅读 90

十三,Spring Boot 中注入 Servlet,Filter,Listener

@

目录

    <li>十三,Spring Boot 中注入 Servlet,Filter,Listener
  • 1. 基本介绍
  • 2. 第一种方式:使用注解方式注入:Servlet,Filter,Listener
    • 2.1 使用注解方式注入:Servlet
    • 2.2 使用注解方式注入:Filter
    • 2.3 使用注解方式注入:Listener
  • 3. 第二种方式:使用 RegistrationBean 方式注入 Servlet,Filter,Listener
    • 3.1 使用 RegistrationBean 方式注入 Servlet
    • 3.2 使用 RegistrationBean 方式注入 Filter
    • 3.3 使用 RegistrationBean 方式注入 Listener
  • 4. 注意事项和细节说明
  • 5. 总结:
  • 6. 最后:

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

使用(<code>@WebServlet + @ServletComponentScan ) 这两个注解方式注入 Servlet

提示: urlPatterns = {"/servlet01","servlet02"},对Servlet配置了url-pat:请求路径的映射

    <li>注入的原生的 Servlet_,不会被Spring boot的拦截器拦截
  • 对于开发的原生的Servlet,需要使用@ServletComponentScan指定要扫描的原生Servlet,才会注入到 Spring容器当中,注意:是在启动场景的位置添加该@ServletComponentScan注解。

在这里插入图片描述

<code>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 容器当中的类。

在这里插入图片描述

<code>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

使用(<code>@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 中表示全部匹配的是: "/**"

在这里插入图片描述

<code>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

使用(<code>@WebListener+ @ServletComponentScan ) 这两个注解方式注入 Servlet

在这里插入图片描述

<code>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

在这里插入图片描述

<code>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 容器当中的类。

在这里插入图片描述

<code>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

在这里插入图片描述

<code>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

在这里插入图片描述

<code>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. 总结:

    <li>

    第一种方式:使用注解方式注入Servlet,Filter,Listener:

    1. 使用(<code>@WebServlet + @ServletComponentScan ) 这两个注解方式注入 Servletli>
    2. 使用(@WebFilter+ @ServletComponentScan ) 这两个注解方式注入 Filter
    3. 使用(@WebListener+ @ServletComponentScan ) 这两个注解方式注入 Servlet
  1. 第二种方式:使用 RegistrationBean 方式注入 Servlet,Filter,Listener 。

  2. 注意:无论是第一种方式还是第二种方式,都必须在对应项目的场景启动器的位置上,使用上: @ServletComponentScan注解。在该注解的 basePackages 属性指明要让 Spring Boot扫描到的包的路径。让 Spring Boot可以找到你想让它注入的 ioc 容器当中的类。

    在这里插入图片描述

    li>

6. 最后:

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

在这里插入图片描述



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。