实战Spring Boot 2.0系列(五) - Listener, Servlet和Filter, Controller和Interceptor

前言

用户认证授权、日志记录 MDC、编码解码、UA 检查、多端对应等都需要通过 拦截请求 来进行处理。这时就需要 ServletFilterListenerInterceptor 这几种组件。而把非 Spring Boot 项目转换成 Spring Boot 项目,需要沿用以前的这些代码,所以有必要了解这它们的 用法生命周期

正文

1. 几种组件介绍

1.1. 监听器Listener

Listener 可以监听 web 服务器中某一个 事件操作,并触发注册的 回调函数。通俗的语言就是在 applicationsessionrequest 三个对象 创建/消亡 或者 增删改 属性时,自动执行代码的功能组件。

1.2. Servlet

Servlet 是一种运行 服务器端java 应用程序,具有 独立于平台和协议 的特性,并且可以动态的生成 web 页面,它工作在 客户端请求服务器响应 的中间层。

1.3. 过滤器Filter

Filter用户请求 进行 预处理,接着将请求交给 Servlet 进行 处理生成响应,最后 Filter 再对 服务器响应 进行 后处理Filter 是可以复用的代码片段,常用来转换 HTTP 请求响应头信息Filter 不像 Servlet,它不能产生 响应,而是只 修改 对某一资源的 请求 或者 响应

1.4. 拦截器Interceptor

类似 面向切面编程 中的 切面通知,我们通过 动态代理 对一个 service() 方法添加 通知 进行功能增强。比如说在方法执行前进行 初始化处理,在方法执行后进行 后置处理拦截器 的思想和 AOP 类似,区别就是 拦截器 只能对 ControllerHTTP 请求进行拦截。

2. 过滤器 VS 拦截器

2.1. 两者的区别

  1. Filter 是基于 函数回调的,而 Interceptor 则是基于 Java 反射动态代理

  2. Filter 依赖于 Servlet 容器,而 Interceptor 不依赖于 Servlet 容器。

  3. Filter 对几乎 所有的请求 起作用,而 Interceptor 只对 Controller 对请求起作用。

2.2. 执行顺序

对于自定义 Servlet 对请求分发流程:

  1. Filter 过滤请求处理;
  2. Servlet 处理请求;
  3. Filter 过滤响应处理。

对于自定义 Controller 的请求分发流程:

  1. Filter 过滤请求处理;
  2. Interceptor 拦截请求处理;
  3. 对应的 HandlerAdapter 处理请求;
  4. Interceptor 拦截响应处理;
  5. Interceptor 的最终处理;
  6. Filter 过滤响应处理。

3. 环境准备

配置gradle依赖

利用 Spring Initializer 创建一个 gradle 项目 spring-boot-listener-servlet-filter-interceptor,创建时添加相关依赖。得到的初始 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.8

repositories {
    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
@SpringBootApplication
public class Application {
   
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

4. 配置监听器Listener

配置一个 ServletContext 监听器,使用 @WebListener 标示即可。在 Servlet 容器 初始化 过程中,contextInitialized() 方法会被调用,在容器 销毁 时会调用 contextDestroyed()

@WebListener
public 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", INITIAL_CONTENT);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        LOGGER.info("Destroy servlet context");
    }
}

这里在容器初始化时,往 ServletContext 上下文设置了参数名称为 INITIAL_CONTENT,可以全局直接访问。

5. 配置Servlet

配置 IndexHttpServlet,重写 HttpServletdoGet() 方法,直接输出 IndexHttpServlet 定义的 初始化参数 和在 IndexServletContextListener 设置的 ServletContext 上下文参数。

@WebServlet(name = "IndexHttpServlet",
        displayName = "indexHttpServlet",
        urlPatterns = {
  "/index/IndexHttpServlet"},
        initParams = {
                @WebInitParam(name = "createdBy", value = "Icarus"),
                @WebInitParam(name = "createdOn", value = "2018-06-20")
        }
)
public class IndexHttpServlet extends HttpServlet {
   
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws IOException {
        resp.getWriter().println(format("Created by %s", getInitParameter("createdBy")));
        resp.getWriter().println(format("Created on %s", getInitParameter("createdOn")));
        resp.getWriter().println(format("Servlet context param: %s",
                req.getServletContext().getAttribute("content")));
    }
}

配置 @WebServlet 注解用于注册这个 Servlet@WebServlet 注解的 各个参数 分别对应 web.xml 中的配置:

<servlet-mapping>  
    <servlet-name>IndexHttpServlet</servlet-name>
    <url-pattern>/index/IndexHttpServlet</url-pattern>
</servlet-mapping>
<servlet>  
    <servlet-name>IndexHttpServlet</servlet-name>  
    <servlet-class>io.ostenant.springboot.sample.servlet.IndexHttpServlet</servlet-class>
    <init-param>
        <param-name>createdBy</param-name>
        <param-value>Icarus</param-value>
    </init-param>
    <init-param>
        <param-name>createdOn</param-name>
        <param-value>2018-06-20</param-value>
    </init-param></
  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值