SpringBoot中使用Servlet,Filter,Listener

Posted 大坑水滴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot中使用Servlet,Filter,Listener相关的知识,希望对你有一定的参考价值。

  项目最近在替换之前陈旧的框架,改用SpringBoot进行重构,初接触,暂时还没有用到Servlet,Filter,Listener的地方,但在之前回顾Servlet的生命周期时,https://www.cnblogs.com/qq931399960/p/10283952.html,想到SpringBoot如何使用原生Servlet,故简单调查了下。

  目前SpringBoot官网GA版本为2.1.2,在官方文档中有对Servlet,Filter,Listener的具体描述

  可以通过将Servlet, Filter,Listener注册为Spring Bean或者使用@ServletComponentScan注解扫描Servlet组件

一、注册Spring Bean方式使用Servlet,Filter,Listener

自定义Servlet

package com.demo.webtest.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("do service"); 
    }

    @Override
    public void destroy() {
        System.out.println("destory servlet");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("init servlet");
    }

}

自定义Filter

package com.demo.webtest.servlet;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {

        System.out.println("do filter");
        // 使请求继续执行
        chain.doFilter(request, response);
    }

    
}

自定义Listener(以ServletRequestListener为例)

package com.demo.webtest.servlet;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

public class MyRequestListener implements ServletRequestListener {

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("destory request");
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("init request");
    }

}

将自定义Servlet,Filter,Listener注册为Spring Bean

package com.demo.webtest.servletbean;

import javax.servlet.Filter;
import javax.servlet.Servlet;
import javax.servlet.ServletRequestListener;

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.stereotype.Component;

import com.demo.webtest.servlet.MyFilter;
import com.demo.webtest.servlet.MyRequestListener;
import com.demo.webtest.servlet.MyServlet;

@Component
public class ServletBean {

    @Bean
    public ServletRegistrationBean<Servlet> registerServlet() {
        ServletRegistrationBean<Servlet> servletRegistrationBean = new ServletRegistrationBean<Servlet>(new MyServlet(),
                "/myservlet");
        // 设置服务启动时初始化该servlet
        servletRegistrationBean.setLoadOnStartup(1);
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean<Filter> registerFilter() {
        FilterRegistrationBean<Filter> filter = new FilterRegistrationBean<>();
        filter.setFilter(new MyFilter());
        filter.addUrlPatterns("/*");
        return filter;
    }

    @Bean
    public ServletListenerRegistrationBean<ServletRequestListener> registerRequestListener() {
        ServletListenerRegistrationBean<ServletRequestListener> servletListenerRegistrationBean = new ServletListenerRegistrationBean<>();
        servletListenerRegistrationBean.setListener(new MyRequestListener());
        return servletListenerRegistrationBean;
    }

}

启动服务

  MyServlet设置了loadOnStartup,且其值大于等于0,故服务启动初始化MyServlet,调用了其init方法,页面访问http://localhost:8080/myservlet

上面日志省略。。。
2019-01-20 09:29:02.308  WARN 12592 --- [           main] ion$DefaultTemplateResolverConfiguration : Cannot find template location: classpath:/templates/ (please add some templates or check your Thymeleaf configuration)
init servlet
2019-01-20 09:29:02.710  INFO 12592 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path \'\'
2019-01-20 09:29:02.712  INFO 12592 --- [           main] com.demo.webtest.WebtestApplication      : Started WebtestApplication in 3.032 seconds (JVM running for 3.47)
init request
do filter
do service
destory request

1、程序启动,初始化Servlet

2、页面访问Servlet,初始化request

3、过滤器过滤请求

4、执行Servlet业务

5、销毁request

清空日志,再次访问http://localhost:8080/myservlet

init request
do filter
do service
destory request

1、初始化request

2、过滤器过滤请求

3、执行Servlet业务

4、销毁request

以上测试时使用的为ServletRequestListener ,LIstener还有其他多种形式,比如HttpSessionListener,HttpSessionBindingListener等,但比较重要的有一个ServletContextListener,在springmvc官网的配置文件中,配置了一个ContextLoaderListener,该Listener实现了ServletContextListener接口,并重写了contextInitialized和contextDestroyed方法,在contextInitialized中初始化了WebApplicationContext,服务器启动后,无论servlet是否配置有loadStartup,也不论该值是什么,contextInitialized始终都在servlet的初始化方法之前执行。每个应用只有一个ServletContext

 

二、使用注解扫描Servlet组件

删除或注释掉ServletBean类

修改自定义Servlet,Filter,Listener,添加Servlet相关组件注解

自定义Servlet,为与上面区分,将url将映射到/my

package com.demo.webtest.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns = "/my", loadOnStartup = 0)
public class MyServlet extends HttpServlet {
     ...
}

自定义Filter

package com.demo.webtest.servlet;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter(urlPatterns="/*")
public class MyFilter implements Filter {
     ...    
}

自定义Listener

package com.demo.webtest.servlet;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;

@WebListener(value="/*")
public class MyRequestListener implements ServletRequestListener {
     ...
}

启动类添加Servlet组件扫描

package com.demo.webtest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;

@SpringBootApplication
@ServletComponentScan
public class WebtestApplication {

    public static void main(String[] args) {
        SpringApplication springApplication = new SpringApplication(WebtestApplication.class);
        springApplication.run(args);
    }
}

服务启动,也会先进行servlet初始化,页面访问http://localhost:8080/my,日志输出与上述注册Spring Bean方式一致

 

以上是关于SpringBoot中使用Servlet,Filter,Listener的主要内容,如果未能解决你的问题,请参考以下文章

过滤器的使用

SpringBoot——SpringBoot中使用Servlet的两种方式

SpringBoot中使用Servlet,方法一

SpringBoot中使用Servlet,Filter,Listener

SpringBoot起飞系列-配置嵌入式Servlet容器

SpringBoot -- 嵌入式Servlet容器