前言
用户认证授权、日志记录 MDC、编码解码、UA 检查、多端对应等都需要通过 拦截请求 来进行处理。这时就需要 Servlet、Filter、Listener、Interceptor 这几种组件。而把非 Spring Boot 项目转换成 Spring Boot 项目,需要沿用以前的这些代码,所以有必要了解这它们的 用法 和 生命周期。
正文
1. 几种组件介绍
1.1. 监听器Listener
Listener 可以监听 web 服务器中某一个 事件操作,并触发注册的 回调函数。通俗的语言就是在 application,session,request 三个对象 创建/消亡 或者 增删改 属性时,自动执行代码的功能组件。
1.2. Servlet
Servlet 是一种运行 服务器端 的 java 应用程序,具有 独立于平台和协议 的特性,并且可以动态的生成 web 页面,它工作在 客户端请求 与 服务器响应 的中间层。
1.3. 过滤器Filter
Filter 对 用户请求 进行 预处理,接着将请求交给 Servlet 进行 处理 并 生成响应,最后 Filter 再对 服务器响应 进行 后处理。Filter 是可以复用的代码片段,常用来转换 HTTP 请求、响应 和 头信息。Filter 不像 Servlet,它不能产生 响应,而是只 修改 对某一资源的 请求 或者 响应。
1.4. 拦截器Interceptor
类似 面向切面编程 中的 切面 和 通知,我们通过 动态代理 对一个 service() 方法添加 通知 进行功能增强。比如说在方法执行前进行 初始化处理,在方法执行后进行 后置处理。拦截器 的思想和 AOP 类似,区别就是 拦截器 只能对 Controller 的 HTTP 请求进行拦截。
2. 过滤器 VS 拦截器
2.1. 两者的区别
- Filter 是基于 函数回调的,而 Interceptor 则是基于 Java 反射 和 动态代理。
- Filter 依赖于 Servlet 容器,而 Interceptor 不依赖于 Servlet 容器。
- Filter 对几乎 所有的请求 起作用,而 Interceptor 只对 Controller 对请求起作用。
2.2. 执行顺序
对于自定义 Servlet 对请求分发流程:
- Filter 过滤请求处理;
- Servlet 处理请求;
- Filter 过滤响应处理。
对于自定义 Controller 的请求分发流程:
- Filter 过滤请求处理;
- Interceptor 拦截请求处理;
- 对应的 HandlerAdapter 处理请求;
- Interceptor 拦截响应处理;
- Interceptor 的最终处理;
- Filter 过滤响应处理。
3. 环境准备
配置gradle依赖
利用 Spring Initializer 创建一个 gradle 项目 spring-boot-web-async-task,创建时添加相关依赖。得到的初始 build.gradle 如下:
buildscript { ext { springBootVersion = '2.0.3.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") }}apply plugin: 'java'apply plugin: 'eclipse'apply plugin: 'org.springframework.boot'apply plugin: 'io.spring.dependency-management'group = 'io.ostenant.springboot.sample'version = '0.0.1-SNAPSHOT'sourceCompatibility = 1.8repositories { mavenCentral()}dependencies { compile('org.springframework.boot:spring-boot-starter-web') testCompile('org.springframework.boot:spring-boot-starter-test')}
配置启动入口类
配置一个 Spring Boot 启动入口类,这里需要配置两个注解。
- @ServletComponentScan: 允许 Spring Boot 扫描和装载当前 包路径 和 子路径 下配置的 Servlet。
- @EnableWvc: 允许 Spring Boot 配置 Spring MVC 相关自定义的属性,比如:拦截器、资源处理器、消息转换器等。
@EnableWebMvc@ServletComponentScan@SpringBootApplicationpublic class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); }}
4. 配置监听器Listener
配置一个 ServletContext 监听器,使用 @WebListener 标示即可。在 Servlet 容器 初始化 过程中,contextInitialized() 方法会被调用,在容器 销毁 时会调用 contextDestroyed()。
@WebListenerpublic class IndexServletContextListener implements ServletContextListener { private static final Logger LOGGER = LoggerFactory.getLogger(IndexServletContextListener.class); public static final String INITIAL_CONTENT = "Content created in servlet Context"; @Override public void contextInitialized(ServletContextEvent sce) { LOGGER.info("Start to initialize servlet context"); ServletContext servletContext = sce.getServletContext(); servletContext.setAttribute("content