SpringBoot 集成原生 Servlet、Filter、Listener

news2024/11/25 12:48:35

注解方式集成 Servlet、Filter、Listener

启动类添加 @ServletComponentScan 注解
@SpringBootApplication
@ServletComponentScan
public class BlogApplication {

    public static void main(String[] args) {
        SpringApplication.run(BlogApplication.class);
    }
}
创建 Servlet (类上添加 @WebServlet 注解)
@Slf4j
@WebServlet(urlPatterns = {"/native_servlet"})
public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String message = "MyServlet doGet";

        log.info(message);

        response.setContentType("text/html");

        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>" + message + "</h1>");
        out.println("</body></html>");
    }
}
创建 Filter (类上添加 @WebFilter 注解)
@Slf4j
@WebFilter
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");
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        log.info("MyFilter destroy");
    }
}
创建 Listener(类上添加 @WebListener 注解)
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        log.info("MyListener contextInitialized");
        ServletContextListener.super.contextInitialized(sce);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        log.info("MyListener contextDestroyed");
        ServletContextListener.super.contextDestroyed(sce);
    }
}
启动项目,访问链接:http://localhost:8080/native_servlet

Servlet、Filter、Listener 都生效了

使用 RegistrationBean 集成 Servlet、Filter、Listener

将方式1类上的相关注解(@ServletComponentScan@WebServlet@WebFilter@WebListener)都注释掉

创建配置类 RegistrationConfig
@Configuration
public class RegistrationConfig {

    @Bean
    public ServletRegistrationBean<MyServlet> myServlet() {
        MyServlet myServlet = new MyServlet();
        return new ServletRegistrationBean<>(myServlet, "/registration_servlet");
    }

    @Bean
    public FilterRegistrationBean<MyFilter> myFilter() {
        MyFilter myFilter = new MyFilter();
        FilterRegistrationBean<MyFilter> filterRegistrationBean = new FilterRegistrationBean<>(myFilter);
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/registration_servlet", "/css/*", "/js/*"));
        return filterRegistrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean<MyListener> myListener() {
        MyListener myListener = new MyListener();
        return new ServletListenerRegistrationBean<>(myListener);
    }
}
启动项目,访问链接:http://localhost:8080/registration_servlet

Servlet、Filter、Listener 都生效了

Interceptor 是否对原生 Servlet 生效?

创建拦截器 FirstInterceptor
@Slf4j
public class FirstInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("FirstInterceptor preHandle");
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("FirstInterceptor postHandle");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("FirstInterceptor afterCompletion");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
创建配置文件 InterceptorConfig
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new FirstInterceptor());
    }
}
创建 DispatcherServletController
@RestController
@RequestMapping
public class DispatcherServletController {

    @RequestMapping("/dispatcher_servlet")
    public String dispatcherServlet() {
        return "dispatcher servlet";
    }

}
访问链接:http://localhost:8080/dispatcher_servlet

FirstInterceptor 生效

再次访问链接:http://localhost:8080/registration_servlet

 FirstInterceptor 对原生 servlet 不生效

Servlet 路径匹配

默认情况下,SpringBoot 只有一个 Servlet (DispatcherServlet),当我们配置了原生的 servlet ,web 容器中就存在两个 Servlet,web 容器根据最佳匹配原则,映射到指定的 Servlet 上

如果 MyServlet 的的匹配路径也是 / ,会发生什么现象?
将 MyServlet 的拦截路径改成 /

在 DispatcherServletController 中添加接口

访问链接 : http://localhost:8080/

通过响应我们可以知道,选择的是 MyServlet(返回的是一个 html)

为什么选择MyServlet?
ServletWebServerApplicationContext#selfInitialize

getServletContextInitializerBeans 的返回值中 MyServlet 的优先级最高且满足最佳匹配,所以会选择 MyServlet

getServletContextInitializerBeans 方法是如何排序的

getServletContextInitializerBeans 方法是通过 AnnotationAwareOrderComparator 排序的,规则如下:

  1. ServletContextInitializer 实现类是否继承 PriorityOrdered 接口,如果都继承 PriorityOrdered 接口,比较 getOrder 方法返回的值,值越小,优先级越高
  2. ServletContextInitializer 实现类是否继承 Ordered 接口,如果都继承 Ordered 接口,比较 getOrder 方法返回的值,值越小,优先级越高
  3. ServletContextInitializer 实现类所属class上是否存在 @Order 注解,如果存在,比较注解设置的值,值越小,优先级越高
  4. ServletContextInitializer 实现类所属class上是否存在 @Priority 注解,如果存在,比较注解设置的值,值越小,优先级越高

DispatcherServletRegistrationBean 继承 RegistrationBean ,RegistrationBean 的 getOrder 方法返回值是 Ordered.LOWEST_PRECEDENCE,对于同样继承 RegistrationBean 的 ServletRegistrationBean 优先级一致,但是 ServletRegistrationBean 解析时机稍后,所以默认情况下优先级更高。

修改 DispatcherServletRegistrationBean 优先级

创建 FirstPostProcessor

@Component
public class FirstPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("dispatcherServletRegistration".equals(beanName) && (bean instanceof DispatcherServletRegistrationBean)) {
            DispatcherServletRegistrationBean dispatcherServletRegistrationBean = (DispatcherServletRegistrationBean) bean;
            dispatcherServletRegistrationBean.setOrder(-1);
        }

        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

 访问链接 : http://localhost:8080/

通过响应我们可以知道,选择的是 DispatcherServlet(返回的是一个字符串) 

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

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

相关文章

免费的会声会影软件哪款拥有最强性能

会声会影2024&#xff1a;引领视频创作新时代的创新之旅** 在数字时代的浪潮中&#xff0c;视频创作已成为连接世界、表达创意的重要方式。随着技术的不断进步&#xff0c;一款名为“会声会影2024”的视频编辑软件横空出世&#xff0c;它不仅继承了前代产品的优秀传统&#xf…

java集成onlyoffice实现文档在线预览编辑

一、onlyoffice是什么 ONLYOFFICE是一款由Ascensio System SIA公司开发的在线办公软件套件&#xff0c;它提供了文档编辑、电子表格、演示文稿和表单等多种办公工具&#xff0c;旨在提高团队协作效率和文档处理的便捷性。以下是关于ONLYOFFICE的详细介绍&#xff1a; 1、软件…

2024年7月30日(nginx 代理 负载均衡 jdk )

一、nginx代理 1、动态服务器 修改index.html文件&#xff0c;并且发布web项目 当前这台主机1动态服务器&#xff0c;后端服务器对标Java服务器&#xff0c;由于没有部署tomcat&#xff0c;所以使用nginx代理 [rootlocalhost ~]# echo "this is web server" > /u…

C++入门 | auto关键字、范围for、指针空值nullptr

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;C专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ C入门 | auto关键字、范围for、指针空值nullptr 文章编号&#xff1a;C …

原神升级计划数据表:重新布局,优化代码

<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>原神升级计划数据表</title><style>* {margin: 0;padding: 0;box-sizing: border-box;body {background: #0b1b2c;}}header {width: 10…

Java斗地主--index1 (0801)

今天遇到一个很有意思的游戏–斗地主&#xff0c;那么下面就开始实现斗地主啦&#xff01;&#xff01;&#xff01; package Demo_YY;public class PockerIndex {public static void main(String[] args) {start();}public static void start(){String pocker[] new String[…

C语言中整数类型及其类型转换

1.数据的存储和排列 是的&#xff0c;在C语言中&#xff0c;整数类型通常以补码&#xff08;twos complement&#xff09;形式存储在内存中。这是因为补码表示法在处理有符号整数的加减运算上更为简便和高效。 基本类型所占字节数&#xff1a; 大端方式存储 就相当于我们平时的…

Android 自定义View(二):画布、画笔、路径(遮罩)以及Sufaceview

目录 1&#xff09;画布是什么&#xff1f;画布如何使用&#xff1f; 2&#xff09;画笔是什么&#xff0c;画笔如何生成呢&#xff1f; 3&#xff09;如何画圆、画文字、画矩形 4&#xff09;路径&#xff08;Path&#xff09;遮罩 5&#xff09;Sufaceview&#xff08;使用…

UWB实操:使用 litepoint 定制UWB信号,BPRF,HPRF,mean PRF,SFD,gap,PSDU,STS

使用 litepoint 定制UWB信号 预备知识: Technology选择UWBP VSG -> WaveGen ->UWBP Wave settings G

2024.8.6 作业

1> 使用消息队列完成两个进程之间相互通信 snd.c #include <myhead.h>struct msgbuf {long mtype;char mtext[1024]; };#define SIZE sizeof(struct msgbuf)-sizeof(long)int main(int argc,const char *argv[]) {pid_t pid fork();if(pid-1){perror("fork er…

【C++入门(下)】—— 我与C++的不解之缘(二)

前言 接上篇&#xff0c;继续来学习C&#xff0c;本篇内容大概有 引用&#xff0c;inline 和 nullptr。 六、引用&#xff1a; 6.1、引用的定义 引用不是新定义一个变量&#xff0c;而是给已存在的变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它…

SQL基础命令

目录 查看版本 root登录 查看用户 数据库清单 创建数据库 选择数据库 删除数据库 退出 MySQL 查看版本 mysql --version root登录 mysql -uroot -p 查看用户 select user()&#xff1b; 数据库清单 show databases; 创建数据库 # create database xxx; create dat…

heic格式批量转化jpg,这几个方法简单好上手!

在这个数字化时代&#xff0c;手机摄影已成为我们记录生活、分享美好的重要方式。然而&#xff0c;苹果用户可能会遇到一个头疼的问题——拍摄的照片默认保存为HEIC格式&#xff0c;这种格式虽然能大幅节省存储空间&#xff0c;但在非苹果设备上查看或编辑时却不太方便。别担心…

8月开始|660/880/严选题45天强化带刷计划

45天刷完《严选题》《660》《880》&#xff1f; 可能吗&#xff1f; 是不是又在制造焦虑&#xff1f; 别急&#xff0c;其实严选题《660》《880》的核心知识点并不多&#xff0c;45天完全能够刷完&#xff0c;下面就是帮大家整理总结的这些习题册的核心知识点和重点题&#…

【多线程-从零开始-肆】线程安全、加锁和死锁

进程状态 进程状态&#xff1a; 就绪&#xff1a;正在 CPU 上执行&#xff0c;或者随时可以去 CPU 上执行阻塞&#xff1a;暂时不能参与 CPU 的执行 Java 的线程&#xff0c;对应状态做了更详细的区分&#xff0c;不仅仅是就绪和阻塞了 六种状态&#xff1a; NEW 当前 Thread…

vulnhub靶机实战_DC-8

一、靶机下载 靶机下载链接汇总&#xff1a;https://download.vulnhub.com/使用搜索功能&#xff0c;搜索dc类型的靶机即可。本次实战使用的靶机是&#xff1a;DC-8系统&#xff1a;Debian下载链接&#xff1a;https://download.vulnhub.com/dc/DC-8.zip 二、靶机启动 下载完…

C++编程基础的学习

Qt跨平台特性 在深入探讨C编程的基础知识之前&#xff0c;我们首先需要了解Qt框架的跨平台特性。Qt是一个功能强大的跨平台应用程序框架&#xff0c;它允许开发者编写一次代码&#xff0c;然后在多个平台上运行&#xff0c;包括Windows、macOS、Linux、iOS、Android等。这种跨…

Linux网络编程3

并发服务器 1.TCP多进程并发服务器 服务器端&#xff1a; 客户端&#xff1a; 2.TCP多线程服务器 服务器端&#xff1a; 客户机端&#xff1a; 需要学习的函数还有 1. send() 函数 send() 函数用于在套接字上发送数据。它是网络编程中发送数据到对端的主要函数之一。 函数…

人像修图-高低频磨皮

原理 将图像分成高频图层&#xff08;处理纹理细节&#xff09;和低频图层&#xff08;处理光影和光影&#xff09;&#xff0c;以达到修饰时互不干扰 步骤 复制两个图层 在低频图层建立高斯模糊&#xff1a;滤镜->模糊->高斯模糊。注意半径一般根据皮肤占比&#xf…

day 20进程

一、程序和进程的区别 程序&#xff1a;保存在磁盘空间中的的一段代码的集合&#xff0c;死的 进程&#xff1a;是一个程序动态执行的过程&#xff0c;包括进程的创建、调度和消亡的过程 二、进程相关的命令 PID:进程的标识符(进程的ID) PPID:父进程的ID号 三、进程的创建…