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方式一致