• 【Spring Boot】Web原生组件注入


    一、闲话

    今天本来准备偷懒一下,但是打开CSDN之前跟自己说,如果今天又涨粉丝了,那么就学习一下
    学多学少都要学,打开一看,哈哈哈,多了三十多个粉丝,只能带着开心来继续学习咯

    二、注入Web原生组件

    1、使用Servlet API

    关于servlet,可以看下博主之前写的博客【SpringMVC】MVC架构与Servlet

    注意,如果要是下面的注解生效,还需要使用@ServletComponentScan注解

    @ServletComponentScan(basePackages = “com.decade.servlet”) :指定原生Servlet组件都放在哪里,我们一般将他放在主启动类上
    在这里插入图片描述

    • 注入Servlet:使用@WebServlet
    package com.decade.servlet;
    
    import lombok.extern.slf4j.Slf4j;
    
    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;
    
    @Slf4j
    @WebServlet(urlPatterns = {"/myServlet"}) // 配置指定url,请求转发到此servlet
    public class MyServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.getWriter().print("test OK!");
        }
    }
    

    效果:直接响应,我们要思考一下/my请求为什么没有经过Spring的拦截器
    在这里插入图片描述

    • 注入Filter:使用@WebFilter
    package com.decade.servlet;
    
    import lombok.extern.slf4j.Slf4j;
    
    import javax.servlet.*;
    import javax.servlet.annotation.WebFilter;
    import java.io.IOException;
    
    @Slf4j
    @WebFilter(urlPatterns = {"/css/*", "/images/*"}) // 配置过滤器过滤的请求
    public class MyFilter implements Filter {
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            log.info("filter初始化完成!");
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            log.info("过滤器生效!");
            // 完成过滤逻辑之后,放行
            filterChain.doFilter(servletRequest, servletResponse);
        }
    
        @Override
        public void destroy() {
            log.info("filter销毁完成!");
        }
    }
    
    • 注入Listener:使用@WebListener
    package com.decade.servlet;
    
    import lombok.extern.slf4j.Slf4j;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    
    @Slf4j
    @WebListener
    public class MyListener implements ServletContextListener {
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
            log.info("MyListener监听到项目初始化完成!");
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
            log.info("MyListener监听到项目销毁!");
        }
    }
    

    启动项目进行验证
    在这里插入图片描述

    2、使用RegistrationBean

    创建一个配置类,使用@Bean注解将servlet、filter和listener注册到容器中去

    我们结合一个实例来验证一下
    首先我们将上面创建的三个类上面的@WebServlet、@WebFilter和@WebListener删除

    然后自己新建一个配置类

    package com.decade.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;
    
    // 保证依赖的组件是单实例的
    @Configuration(proxyBeanMethods = true)
    public class MyServletConfig {
    
        @Bean
        public ServletRegistrationBean myServlet() {
            final MyServlet myServlet = new MyServlet();
            // 设置对应此servlet的请求路径
            return new ServletRegistrationBean(myServlet, "/myServlet", "/myServlet2");
        }
    
        @Bean
        public FilterRegistrationBean myFilter() {
            final MyFilter myFilter = new MyFilter();
            // 设置要过滤的请求,即对应这个请求的servlet
            //return new FilterRegistrationBean(myFilter, myServlet());
    
    		// 方式二:使用setUrlPatterns配置要拦截的请求
            FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(myFilter);
            filterRegistrationBean.setUrlPatterns(Arrays.asList("/css/*", "/myServlet", "/myServlet2"));
            return filterRegistrationBean;
        }
    
        @Bean
        public ServletListenerRegistrationBean myListener() {
            final MyListener myListener = new MyListener();
            return new ServletListenerRegistrationBean(myListener);
        }
    }
    

    验证同样生效
    在这里插入图片描述

    3、思考

    /my请求为什么没有经过Spring的拦截器?

    那么我们就要考虑一下DispatcherServlet类是怎么注册到容器中的
    我们需要分析下和DispatcherServlet有关的自动配置类DispatcherServletAutoConfiguration

    • 它下面有一个配置类DispatcherServletConfiguration,向容器中注册了DispatcherServlet,并将属性绑定到 WebMvcProperties,点进去可以看到对应的配置文件配置项是spring.mvc
      在这里插入图片描述

    • 然后这里还有一个配置类DispatcherServletRegistrationConfiguration,它里面有一个方法dispatcherServletRegistration(),这里就和我们上面第二节的作用是一样的,使用RegistrationBean把DispatcherServlet这个类当作Servlet组件注册到容器中
      在这里插入图片描述

    了解了上述原理之外,我们还需要了解一个原则,
    精确优选原则:如果一个请求能被两个Servlet处理,那么我们先选匹配精确度高的那个

    这就解释了为什么,我们自定义的Servlet对应的请求没有被我们系统中配置的拦截器拦截,因为他直接走了tomcat,没有走Spring默认配置的DispatcherServlet类下的doDispatch()方法,我们拦截器的前置和后置等操作都在这个方法中进行

    如有错误,欢迎指正!!!

  • 相关阅读:
    Python学习 -- datetime模块
    [开源预告]开源用两千元做的水下机器人方案
    Java继承基础。
    redis五种数据类型
    消息队列-------Rabbitmq介绍和安装
    游戏类app有哪些变现方式?
    通过股票量化交易券商接口如何减少发生亏损的风险?
    Python:每日一题之拉马车
    ROS参数名称设置
    案例分享 | 纽扣电池石墨片厚度及缺陷检测
  • 原文地址:https://blog.csdn.net/Decade0712/article/details/126943982