Java Web三大组件

传统Java web项目

  • 最常用的三大组件有ServletFilterListener。使用这些组件时需要在项目的web.xml文件中进行配置,或者使用相应的注解进行标注。

Spring Boot项目

  • 默认没有web.xml文件,同时默认情况下Spring Boot项目不能自动识别到这三个组件的相关注解。可以使用Spring BeanRegistrationBean注解扫描的方式注册Java Web三大组件。

在Spring Boot项目中由于默认大于配置,会自动将Spring容器中的ServletFilterListener实例注册为Web服务器中对应的组件。因此,可以将自定义的Java Web三大组件作为Bean添加到Spring容器中,以实现组件的注册。

Servlet测试

  • SecondServlet
/**
 * @Title: SecondServlet
 * @Author David
 * @Package com.work.spring.springbootwork.Servlet
 * @Date 2024/9/14 下午4:37
 * @description:
 */
public class SecondServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Hello SecondServlet!");
        resp.getWriter().write("Hello SecondServlet!");
    }
}
  • FirstServlet
/**
 * @Title: FirstServlet
 * @Author David
 * @Package com.work.spring.springbootwork.Servlet
 * @Date 2024/9/14 下午4:34
 * @description:
 */
public class FirstServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("Hello FirstServlet!");
        response.getWriter().write("Hello FirstServlet!");
    }
}

Filter测试

  • MyFilter
/**
 * @Title: MyFilter
 * @Author David
 * @Package com.work.spring.springbootwork.filter
 * @Date 2024/9/14 下午4:39
 */
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("处理请求前的处理");
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("处理请求后的处理");
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}

Listener测试

  • MyListener
/**
 * @Title: MyListener
 * @Author David
 * @Package com.work.spring.springbootwork.listener
 * @Date 2024/9/14 下午4:43s
 */
public class MyListener implements ServletContextListener {
    public  void contextInitialized(ServletContextEvent sce) {
        System.out.println("----Web 应用初始化完成----");
    }

    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("----Web 应用销毁之前----");
    }
}

将Servlet、Filter和Listener通过@Configuration加入Bean

  • WebConfigure

:::note 所有文件通过@Configuration + @Bean注册进入Bean容器

不用测试Servlet用Bean注入会有生命周期的问题得使用RegistrationBean :::

/**
 * @Title: WebConfigure
 * @Author David
 * @Package com.work.spring.springbootwork.config
 * @Date 2024/9/14 下午4:46
 */
@Configuration
public class WebConfigure {

    @Bean("firstServlet")
    public FirstServlet firstServlet() {
        return new FirstServlet();
    }

    @Bean("secondServlet")
    public SecondServlet secondServlet() {
        return new SecondServlet();
    }

    @Bean
    public MyFilter myFilter() {
        return new MyFilter();
    }

    @Bean
    public MyListener myListener() {
        return new MyListener();
    }
}

测试成功截图

  • FirstServlet
20240903220327.png

FirstServlet测试成功截图

  • SecondServlet
20240903220327.png

SecondServlet测试成功截图

  • MyFilter
20240903220327.png

MyFilter测试成功截图

  • Listener
20240903220327.png

Listener测试成功截图

使用Spring Bean注册Servlet时,需要自定义两个及以上的Servlet,Servlet对应的映射地址为“Bean名称+/”。Filter的映射地址默认为“/*”。

RegistrationBean注册三大组件

  • 使用Spring Bean注册Java Web三大组件时,如果容器中只有一个自定义Servlet,则无法使用Bean的名称作为映射路径,而Filter默认只使用“*”的映射地址。为解决此问题Spring Boot提供了更为灵活的注册方法,可以在配置类中使用 RegistrationBean来注册原生Web组件。
  • RegistrationBean是个抽象类,SpringBoot提供了三个RegistrationBean的实现类:ServletRegistrationBeanFilterRegistrationBeanServletListenerRegistrationBean,这三个类分别用来注册Servlet、Filter和Listener,通过这三个类开发者可以获得自定义映射路径等更多的控制权

RegistrationBean常用方法:

1. ServletRegistrationBean

ServletRegistrationBean 用于将自定义的 Servlet 注册到 Spring Boot 的嵌入式容器(如 Tomcat、Jetty)中,并进行一些初始化配置。

  1. ServletRegistrationBean(T servlet, String... urlMappings)
    • 用于初始化 Servlet,并设置 URL 映射。
    • 参数
      • servlet: 需要注册的 Servlet 实例。
      • urlMappings: 该 Servlet 映射的 URL 模式(例如 "/myServlet/*")。

/myServlet 是通过 ServletRegistrationBean 的构造方法传递的 URL 映射路径,它实际上就是通过 addUrlMappings 方法设置的地址,用于定义该 Servlet 处理请求的路径。

  1. setLoadOnStartup(int loadOnStartup)
    • 设置 Servlet 的加载优先级。值越小优先级越高,默认值是 -1

    • 示例

      registrationBean.setLoadOnStartup(1);
      
  • 加载时机:loadOnStartup 值决定了 Servlet 的加载时机。默认值为 -1,意味着 Servlet 会在收到首次请求时才被加载。如果设置为正整数,Servlet 会在服务器启动时立即加载。

  • 优先级:正整数值还表示加载的优先级,值越小优先级越高。例如,0 表示最高优先级,1 表示次高优先级,以此类推。负数值(如 -1)意味着懒加载,也就是直到有请求到达该 Servlet 时才加载。

  1. setName(String name)
    • 设置 Servlet 的名称。

    • 示例

      registrationBean.setName("MyServlet");
      

而是这个 Servlet 的逻辑名称,主要用于在日志、监控工具或者容器管理中对 Servlet 进行标识

  1. addUrlMappings(String... urlMappings)
    • 添加 URL 映射,指定 Servlet 将处理哪些请求路径。

    • 示例

      registrationBean.addUrlMappings("/customServlet/*");
      

添加 URL 映射,指定该 Servlet 处理 "/customServlet/*" 路径的请求

  1. setAsyncSupported(boolean isAsyncSupported)
    • 设置是否支持异步处理。

    • 示例

      registrationBean.setAsyncSupported(true);
      

异步处理允许 Servlet 在处理请求时不阻塞当前线程。当设置 setAsyncSupported(true) 时,Servlet 就可以使用异步处理机制,将任务交给另一个线程来处理,而当前线程可以立即释放,处理其他请求

  1. setInitParameters(Map<String, String> initParameters)
    • 设置 Servlet 初始化参数。

    • 示例

      Map<String, String> params = new HashMap<>();
      params.put("config", "value");
      registrationBean.setInitParameters(params);
      
  • 初始化参数:这些参数在 Servlet 初始化阶段传递,并且只能在 Servlet 的生命周期内使用,通常通过 ServletConfig.getInitParameter() 方法来访问。

  • 用途:初始化参数通常用于配置 Servlet 的一些基本信息,比如数据库连接信息、特定行为开关、静态文件路径等。

  1. setEnabled(boolean enabled)
    • 启用或禁用 Servlet,默认是启用的。

    • 示例

      registrationBean.setEnabled(false);
      

这对于某些场景很有用,比如在开发或测试环境中,临时禁用某些 Servlet,而不需要修改其他配置。


2. FilterRegistrationBean

FilterRegistrationBean 用于将自定义的 Filter 注册到 Spring Boot 的嵌入式容器中,通常用于拦截和处理 HTTP 请求。

  1. FilterRegistrationBean(T filter)

    • 构造器,用于注册 Filter

    • 参数

      • filter: 需要注册的 Filter 实例。
    • 示例

      // T filter是泛类的意思
      public FilterRegistrationBean<MyFilter> myFilterBean(){}
      
  2. addUrlPatterns(String... urlPatterns)

    • 添加过滤器要处理的 URL 模式。

    • 示例

      registrationBean.addUrlPatterns("/api/*");
      
  3. setOrder(int order)

    • 设置过滤器的执行顺序,数字越小优先级越高。

    • 示例

      registrationBean.setOrder(1); // 优先级高
      

使用场景为,有多个filter过滤器的时候可以对请求进行多次处理

  1. setServletNames(String... servletNames)
    • 为指定的 Servlet 配置过滤器。这个方法允许你将过滤器应用于特定的 Servlet

    • 示例

      registrationBean.setServletNames("MyServlet");
      

是一个逻辑名称,方便日志观察

  1. setEnabled(boolean enabled)
    • 启用或禁用 Filter,默认是启用的。

    • 示例

      registrationBean.setEnabled(false); // 禁用过滤器
      

通过boolean值去控制拦截器是否生效,可以用配置文件动态的配置,适合分布式系统使用

  1. setDispatcherTypes(DispatcherType... dispatcherTypes)
    • 设置过滤器处理的调度类型,如 REQUESTFORWARDINCLUDEERROR 等。

    • 示例

      registrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD);
      

setDispatcherTypes 方法指定了过滤器在哪些调度类型下生效。你可以通过这个方法精确控制过滤器在处理哪些类型的请求时触发。

REQUEST:表示处理客户端发来的请求。这个是最常见的调度类型,通常处理所有直接的 HTTP 请求。

FORWARD:当一个 Servlet 或 JSP 通过 RequestDispatcher.forward() 将请求转发给另一个资源时,这个调度类型会被触发。

INCLUDE:当一个 Servlet 或 JSP 通过 RequestDispatcher.include() 将另一个资源的输出包含在自己的响应中时,触发该类型。

ERROR:当请求发生错误并进入错误处理阶段时,这个类型会被触发。

ASYNC:与异步处理相关的调度类型。

  1. setInitParameters(Map<String, String> initParameters)
    • 设置过滤器的初始化参数。

    • 示例

      Map<String, String> params = new HashMap<>();
      params.put("encoding", "UTF-8");
      registrationBean.setInitParameters(params);
      

你可以让过滤器的配置更加灵活。例如,你可以在不同环境中为同一个过滤器提供不同的配置参数,而不需要修改代码

filterConfig.getInitParameter("encoding")获取参数


3. ServletListenerRegistrationBean

ServletListenerRegistrationBean 用于将 ServletContextListener 或其他 Listener 注册到 Spring Boot 的容器中,用来监听 Servlet 容器的生命周期或某些特定事件。

  1. ServletListenerRegistrationBean(T listener)

    • 构造器,用于注册 Listener

    • 参数

      • listener: 需要注册的 Listener 实例。
    • 示例

      ServletListenerRegistrationBean<MyListener> listenerBean = new ServletListenerRegistrationBean<>(new MyListener());
      
  2. setListener(T listener)

    • 设置监听器实例。

    • 示例

      listenerRegistrationBean.setListener(new MyListener());
      
  3. setEnabled(boolean enabled)

    • 启用或禁用 Listener,默认是启用的。

    • 示例

      listenerRegistrationBean.setEnabled(true);
      
  4. setOrder(int order)

    • 设置监听器的优先级,类似于 Filter,数字越小优先级越高。

    • 示例

      listenerRegistrationBean.setOrder(1);
      

方法调用的常见使用场景

  • ServletRegistrationBean

    • 使用场景:注册自定义 Servlet,例如动态生成内容的 Servlet
    • 常见配置:addUrlMappingssetLoadOnStartupsetAsyncSupported
  • FilterRegistrationBean

    • 使用场景:拦截和处理 HTTP 请求,如安全过滤、日志过滤、字符编码设置等。
    • 常见配置:addUrlPatternssetOrdersetInitParameters
  • ServletListenerRegistrationBean

    • 使用场景:监听 Web 应用程序生命周期事件,例如应用启动或关闭时执行一些任务。
    • 常见配置:setListenersetOrder

修改Sverlet

  • 修改WebConfigure内容
/**
 * @Title: WebConfigure
 * @Author David
 * @Package com.work.spring.springbootwork.config
 * @Date 2024/9/14 下午4:46
 */
@Configuration
public class WebConfigure {

    @Bean
    public FilterRegistrationBean<MyFilter> myFilterBean() {
        FilterRegistrationBean<MyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new MyFilter());
        registrationBean.addUrlPatterns("/*"); // 设置过滤的 URL 模式
        registrationBean.setOrder(1); // 过滤器的执行顺序,数字越小优先级越高
        return registrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean<MyListener> myListenerBean() {
        ServletListenerRegistrationBean<MyListener> listenerRegBean = new ServletListenerRegistrationBean<>();
        listenerRegBean.setListener(new MyListener());
        return listenerRegBean;
    }

    @Bean("FirstServlet")
    public ServletRegistrationBean<FirstServlet> firstServlet() {
        ServletRegistrationBean<FirstServlet> bean = new ServletRegistrationBean<>(new FirstServlet(), "/firstServlet");
        bean.setName("FirstServlet");
        bean.setLoadOnStartup(1); // 设置优先级
        return bean;
    }
    
}

@ServletComponentScan注解扫描

  • Servlet测试
@WebServlet(name = "FirstServlet", urlPatterns = "/firstServlet/*")
public class FirstServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("Hello FirstServlet!");
        response.getWriter().write("Hello FirstServlet!");
    }
}
  • Listener测试
/**
 * @Title: MyListener
 * @Author David
 * @Package com.work.spring.springbootwork.listener
 * @Date 2024/9/14 下午4:43s
 */
@WebListener
public class MyListener implements ServletContextListener {
    public  void contextInitialized(ServletContextEvent sce) {
        System.out.println("----Web 应用初始化完成----");
    }

    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("----Web 应用销毁之前----");
    }
}
  • Filter测试
/**
 * @Title: MyFilter
 * @Author David
 * @Package com.work.spring.springbootwork.filter
 * @Date 2024/9/14 下午4:39
 */
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        Filter.super.init(filterConfig);
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("处理请求前的处理");
        filterChain.doFilter(servletRequest, servletResponse);
        System.out.println("处理请求后的处理");
    }

    @Override
    public void destroy() {
        Filter.super.destroy();
    }
}
  • 启动类添加@ServletComponentScan
@SpringBootApplication
@ImportResource("classpath:beans.xml")
@ServletComponentScan
public class SpringBootWorkApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringBootWorkApplication.class, args);
    }
}