Spring filter原理深入浅出

来源:互联网 发布:手机淘宝宝贝描述模板 编辑:程序博客网 时间:2024/06/03 20:46

title: Spring filter原理深入浅出

tag: Spring

date: 2017-12-21 16:05:00

categories: Spring


Spring filter原理深入浅出

在这篇文章中,我会介绍一个请求从浏览器进来,是如何被Spring拦截到的,Spring又是如何处理这个请求的,filter有什么作用,filter的原理等

一、前置知识

OK,我们首先介绍一下,请求从浏览器过来,我们的服务器会经历些什么。先看一张jetty的内部结构图

jetty内部组成

我们看到jetty的核心组件包括了一大堆的*Handler ,对于这些handler,不论任何容器基本都有,可能名称不太相同,笔者这里以undertow这个容器为例,浏览器发送过来的请求,会经过一个FilterHandler 这个handler跟我们今天的主题相关。

二、Request阶段

先看一下这个handler的处理代码

public void handleRequest(HttpServerExchange exchange) throws Exception {        ServletRequestContext servletRequestContext = (ServletRequestContext)exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);        ServletRequest request = servletRequestContext.getServletRequest();        ServletResponse response = servletRequestContext.getServletResponse();        DispatcherType dispatcher = servletRequestContext.getDispatcherType();        Boolean supported = (Boolean)this.asyncSupported.get(dispatcher);        if (supported != null && !supported.booleanValue()) {            servletRequestContext.setAsyncSupported(false);        }        List<ManagedFilter> filters = (List)this.filters.get(dispatcher);        if (filters == null) {            this.next.handleRequest(exchange);        } else {            FilterHandler.FilterChainImpl filterChain = new FilterHandler.FilterChainImpl(exchange, filters, this.next, this.allowNonStandardWrappers);            filterChain.doFilter(request, response);        }    }

前面都是拿request和response我们不用看,主要是看后面几行代码,filters 如果我们有配置自己的filter,这里肯定不会为空,那么就走下面的filter 链 ,我们看下FilterHandler里面的doFilter的代码

int index = this.location++;if (index >= this.filters.size()) {  this.next.handleRequest(this.exchange);} else {  ((ManagedFilter)this.filters.get(index)).doFilter(request, response, this);}

​ location默认是0,所以会从list里面的第一个元素取起,依次执行,OK,我们知道,filter里面一般会有一个filterChain.doFilter(request, response); 这句话,代表filter链继续执行,这时候,这里的location就会+1 ,变成执行第二个,第三个,链条就转动起来了。终于执行到我们自己写的ResponseWrapperFilter ,这个filter大家可以在我后面的源码里看到,这里我先说有这么一个自己写的filter,我用来包装我们的response,给response做些手脚。哈哈。

​ OK,我们继续,当所有的filter都执行完毕之后,就会开始执行this.next.handleRequest(exchange); 这段代码,也就是在继续执行我们刚才的handler链,next表示的是ServletHandler` 这个类,执行代码如下。

try {                servlet = this.managedServlet.getServlet();                ((Servlet)servlet.getInstance()).service(request, response);            } catch (UnavailableException var12) {                if (var12.isPermanent()) {                    UndertowServletLogger.REQUEST_LOGGER.stoppingServletDueToPermanentUnavailability(this.managedServlet.getServletInfo().getName(), var12);                    this.managedServlet.stop();                    this.managedServlet.setPermanentlyUnavailable(true);                    exchange.setStatusCode(404);                } else {                    unavailableUntilUpdater.set(this, System.currentTimeMillis() + (long)(var12.getUnavailableSeconds() * 1000));                    UndertowServletLogger.REQUEST_LOGGER.stoppingServletUntilDueToTemporaryUnavailability(this.managedServlet.getServletInfo().getName(), new Date(until), var12);                    exchange.setStatusCode(503); }

一旦掉用了下面这段代码,我们的处理逻辑就会被调用,说白了就是我们Controller里面的那些逻辑就会被调用

 ((Servlet)servlet.getInstance()).service(request, response);

这段代码很重要

三、reponse阶段

​ 经过了上面这段代码的执行,我们的filter开始收拢了,所有的filter在执行filterChain.doFilter(request, response);这段代码之后其实代码是还没有执行完的,如果你下面还有写代码的话,大家好好品味一下这句话,是不是这个意思。因为每个filter都去调用下一个filter了,等最后一个filter执行完毕之后,就开始慢慢收拢,这时候我们的reponse也有了。

​ 当所有的filter执行完毕自己的后置代码之后,就回到了我们最初的地方,我们的最初的FilterHandler开始调用的地方。undertow服务器就继续开始执行了,它就会执行下面的代码输出你想要的信息

if (!exchange.isDispatched() && !(exchange.getConnection() instanceof ServletInitialHandler.MockServerConnection)) {            servletRequestContext.getOriginalResponse().responseDone();            servletRequestContext.getOriginalRequest().clearAttributes();        }

主要就是把输出流写入到socket中,然后客户端接收

好啦,今天就讲到这里啦,这文章还没有结束,请期待后续 ^ _ ^

原创粉丝点击