(四)Tomcat架构及运行原理之请求处理

本文详细解析了Tomcat中请求的处理流程,从Processor到Adapter,再到StandardPipeline及其Valve组件,直至ApplicationFilterChain,深入介绍了各组件的功能与交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 请求的处理及Container通信

1.1 Processor

1.1.1 AbstractProcessorLight

1.1.2 AbstractProcessor

1.1.3 Http11Processor

1.2 Adapter

1.3 StandardPipeline

1.4 StandardEngineValve

1.5 StandardHostValve

1.6 StandardContextValve

1.7 StandardWrapperValve

1.8 ApplicationFilterChain

在阅读本篇笔记前请先看(三)Tomcat架构及运行原理之Connector源码分析文章。

1. 请求的处理及Container通信

1.1 Processor

在上篇笔记中,我们已经介绍过了Connector中是如何从Container调用到Connector中,而Connector又是如何创建Socket监听机制以及和本篇需要讲的对具体请求进行处理入口。本篇着重于从handler到Servlet整个流程的通信。先看到关键的processor接口源码:

public interface Processor {
    SocketState process(SocketWrapperBase<?> socketWrapper, 
            SocketEvent status) throws IOException;
    UpgradeToken getUpgradeToken();
    boolean isUpgrade();
    boolean isAsync();
    void timeoutAsync(long now);
    Request getRequest();
    void recycle();
    void setSslSupport(SSLSupport sslSupport);
    ByteBuffer getLeftoverInput();
    void pause();
    boolean checkAsyncTimeoutGeneration();
}

本接口process接口无疑是最重要的,但是getRequest方法和recycle方法也是需要注意的。

1.1.1 AbstractProcessorLight

首先看到Processor接口的实现子类AbstractProcessorLight。其部分关键源码如下:

public abstract class AbstractProcessorLight implements Processor {
    @Override
    public SocketState process(SocketWrapperBase<?> socketWrapper, 
            SocketEvent status)
            throws IOException {
        // 设置为CLOSED是为了等下不用再设置状态而可以直接跳出do-while循环
        SocketState state = SocketState.CLOSED;
        Iterator<DispatchType> dispatches = null;
        do {
            // 中间的调用dispatch可以忽略,因为和HTTP请求无关
            // Websocket才会用到
            if (dispatches != null) {
                ...
            } else if (status == SocketEvent.OPEN_READ){
                // 执行HTTP请求方法,具体实现交给子类实现
                state = service(socketWrapper);
            } else {
                state = SocketState.CLOSED;
            }
            // 异步执行
            if (state != SocketState.CLOSED && isAsync()) {
                state = asyncPostProcess();
            }
            if (dispatches == null || !dispatches.hasNext()) {
                dispatches = getIteratorAndClearDispatches();
            }
        } while (state == SocketState.ASYNC_END ||
                dispatches != null && state != SocketState.CLOSED);
        return state;
    }
    protected abstract SocketState service(
            SocketWrapperBase<?> socketWrapper) throws IOException;
    protected abstract SocketState dispatch(SocketEvent status) 
            throws IOException;
}

本类也只是一个模板方法,在父类中确定根据哪些状态去执行哪些方法。普通的HTTP请求和service相关,而诸如Websocket和dispatch相关。

1.1.2 AbstractProcessor

这个类起到承上启下的作用。其部分关键源码如下:

public abstract class AbstractProcessor extends AbstractProcessorLight 
        implements ActionHook {
    protected final Adapter adapter;
    protected final Request request;
    protected final Response response;
    protected volatile SocketWrapperBase<?> socketWrapper = null;
    protected volatile SSLSupport sslSupport;
    public AbstractProcessor(Adapter adapter) {
        this(adapter, new Request(), new Response());
    }
    protected AbstractProcessor(Adapter adapter, Request coyoteRequest, 
            Response coyoteResponse) {
        this.adapter = adapter;
        asyncStateMachine = new AsyncStateMachine(this);
        request = coyoteRequest;
        response = coyoteResponse;
        response.setHook(this);
        request.setResponse(response);
        request.setHook(this);
        userDataHelper = new UserDataHelper(getLog());
    }
}

可以看到,这个类关键的代码很少(指的是在启动Tomcat时和普通的HTTP请求进来时,关键部分只是这一部分代码)。其关键则是设置Adapter、request和response对象,需要注意的是此时的request和response是org.apache.coyote包下的,和我们平时见到的不是同一个。

1.1.3 Http11Processor

其部分关键源码如下:

public class Http11Processor extends AbstractProcessor {
    private final AbstractHttp11Protocol<?> protocol;
    private final Http11InputBuffer inputBuffer;
    private final Http11OutputBuffer outputBuffer;
    private final HttpParser httpParser;
    public Http11Processor(AbstractHttp11Protocol<?> protocol, 
            Adapter adapter) {
        super(adapter);
        this.protocol = protocol;
        httpParser = new HttpParser(protocol.getRelaxedPathChars(),
                protocol.getRelaxedQueryChars());
        inputBuffer = new Http11InputBuffer(request, 
                protocol.getMaxHttpHeaderSize(),
                protocol.getRejectIllegalHeaderName(), httpParser);
        request.setInputBuffer(inputBuffer);
        outputBuffer = new Http11OutputBuffer(response, 
                protocol.getMaxHttpHeaderSize());
        response.setOutputBuffer(outputBuffer);
        inputBuffer.addFilter(new IdentityInputFilter(
                protocol.getMaxSwallowSize()));
        outputBuffer.addFilter(new IdentityOutputFilter());
        inputBuffer.addFilter(new ChunkedInputFilter(protocol
                .getMaxTrailerSize(),
                protocol.getAllowedTrailerHeadersInternal(), 
                protocol.getMaxExtensionSize(),
                protocol.getMaxSwallowSize()));
        outputBuffer.addFilter(new ChunkedOutputFilter());
        inputBuffer.addFilter(new VoidInputFilter());
        outputBuffer.addFilter(new VoidOutputFilter());
        inputBuffer.addFilter(new BufferedInputFilter());
        outputBuffer.addFilter(new GzipOutputFilter());
        pluggableFilterIndex = inputBuffer.getFilters().length;
    }
    @Override
    public SocketState service(SocketWrapperBase<?> socketWrapper)
        throws IOException {
        // 先对参数进行初始化,略过
        ...
        while (!getErrorState().isError() && keepAlive && !isAsync() && 
                upgradeToken == null &&
                sendfileState == SendfileState.DONE && 
                !protocol.isPaused()) {
            // 中间验证request、设置request和判断Upgrade的流程便略过
            ...
            if (getErrorState().isIoAllowed()) {
                try {
                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
                    // 获得Adapter去调用service
                    // 这里的Adapter实则是CoyoteAdapter类型
                    getAdapter().service(request, response);
                    if(keepAlive && !getErrorState().isError() && 
                            !isAsync() &&
                            statusDropsConnection(response.getStatus())) {
                        setErrorState(ErrorState.CLOSE_CLEAN, null);
                    }
                } catch (InterruptedIOException e) {
                    ...
                } 
            }
            // 状态的判断略过
            ...
            sendfileState = processSendfile(socketWrapper);
        }
        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
        // 状态返回略过
        ...
    }
    @Override
    public final void recycle() {
        getAdapter().checkRecycled(request, response);
        super.recycle();
        inputBuffer.recycle();
        outputBuffer.recycle();
        upgradeToken = null;
        socketWrapper = null;
        sendfileData = null;
        sslSupport = null;
    }
}

 该类中一共只有三个方法需要留意:构造函数,service方法和recycle。构造函数确定了类中对象的具体类型,而recycle方法则是将类中的各个属性设置为最开始的状态。service方法在代码中进行了说明,其它流程都是对状态和结果的判断,最重要的便是调用adapter的service方法。

1.2 Adapter

终于到了Adapter来了,这个类的作用便是将Connector组件的类调用到Container类中,当然Container中的组件通信都是使用管道来通信的,因此Adapter实际上对接的是Connector和Pipeline。

其部分关键源码如下:

public class CoyoteAdapter implements Adapter {
    private final Connector connector;
    public CoyoteAdapter(Connector connector) {
        super();
        this.connector = connector;
    }
    @Override
    public void service(org.apache.coyote.Request req, 
            org.apache.coyote.Response res)
            throws Exception {
        // 将org.apache.coyote包下的request和response转换成
        // org.apache.catalina.connector包下继承HttpServletRequest类型
        Request request = (Request) req.getNote(ADAPTER_NOTES);
        Response response = (Response) res.getNote(ADAPTER_NOTES);
        if (request == null) {
            request = connector.createRequest();
            request.setCoyoteRequest(req);
            response = connector.createResponse();
            response.setCoyoteResponse(res);
            request.setResponse(response);
            response.setRequest(request);
            req.setNote(ADAPTER_NOTES, request);
            res.setNote(ADAPTER_NOTES, response);
            req.getParameters().setQueryStringCharset(
                    connector.getURICharset());
        }
        // 中间略过
        ...
        try {
            // 解析并设置Catalina核心属性和特定请求配置,如host、context、
            // 参数、请求方式、允许的请求方式和版本等信息
            // 当然,非常重要的信息就是根据请求路径来判断由哪个
            // StandardWrapper处理这个请求也是在这里面完成的
            postParseSuccess = 
                    postParseRequest(req, request, res, response);
            if (postParseSuccess) {
                // 检查是否支持异步止回阀
                request.setAsyncSupported(
                        connector.getService().getContainer()
                        .getPipeline().isAsyncSupported());
                // 调用进Container中,这里是关键,由Connector部分调用进了
                // Container,完成两者的适配
                connector.getService().getContainer().getPipeline()
                        .getFirst().invoke(request, response);
            }
            ...
        } catch (IOException e) {
            ...
        } finally {
            ...
        }
    }
}

可以看到,Adapter从名字便可以看出来这是个适配器,从其关键源码的实现可以看出来其适配了Connector和Container,使Connector能够成功的调用进Container。在这里面也完成了request和response的类型转换,将Connector组件中的转换成了Container中的。

1.3 StandardPipeline

各个容器都是使用StandardPipeline管道类来进行连通的,同时管道中又保存了Valve阈的关联关系,可以看到其关键部分源码:

public class StandardPipeline extends LifecycleBase implements Pipeline {
    protected Container container = null;
    protected Valve basic = null;
    protected Valve first = null;
    @Override
    public Valve getFirst() {
        if (first != null) {
            return first;
        }
        return basic;
    }
}

从其关键源码中便可以得知这个类只是一个中介类(主要负责连接的管道当然只负责连接对方,而不需要进行逻辑操作),保存了Container和处理管道对应的valve阈。

1.4 StandardEngineValve

Container的运行架构图便不再这里赘述,看过前面总体架构分析便能得知。其关键源码如下:

final class StandardEngineValve extends ValveBase {
    protected Container container = null;
    protected Valve next = null;
    @Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        Host host = request.getHost();
        if (host == null) {
            return;
        }
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(host.getPipeline()
                    .isAsyncSupported());
        }
        host.getPipeline().getFirst().invoke(request, response);
    }
}

该类实际上只对host进行了某些判断,并直接获得host调用其管道进行下个容器的流程。

1.5 StandardHostValve

其关键源码如下:

final class StandardHostValve extends ValveBase {
    protected Container container = null;
    protected Valve next = null;
    @Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        Context context = request.getContext();
        if (context == null) {
            return;
        }
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(context.getPipeline()
                    .isAsyncSupported());
        }
        boolean asyncAtStart = request.isAsync();
        try {
            context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
            if (!asyncAtStart && 
                    !context.fireRequestInitEvent(request.getRequest())) {
                return;
            }
            try {
                if (!response.isErrorReportRequired()) {
                    // 继续执行管道连接的下个Container方法
                    context.getPipeline().getFirst()
                            .invoke(request, response);
                }
            } catch (Throwable t) {
                ...
            }
            // 后置处理
            ...
        } finally {
            if (ACCESS_SESSION) {
                request.getSession(false);
            }
            context.unbind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
        }
    }
}

该阈和上一个差不了多少,也只是对request和response进行一些状态处理。

1.6 StandardContextValve

其关键源码如下:

final class StandardContextValve extends ValveBase {
    protected Container container = null;
    protected Valve next = null;
    @Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        // 如果不允许直接访问WEB-INF或META-INF下的资源
        MessageBytes requestPathMB = request.getRequestPathMB();
        if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0))
                || (requestPathMB.equalsIgnoreCase("/META-INF"))
                || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0))
                || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        Wrapper wrapper = request.getWrapper();
        if (wrapper == null || wrapper.isUnavailable()) {
            response.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        try {
            // 确认请求
            response.sendAcknowledgement();
        } catch (IOException ioe) {
            ...
        }
        if (request.isAsyncSupported()) {
            request.setAsyncSupported(wrapper.getPipeline()
                    .isAsyncSupported());
        }
        wrapper.getPipeline().getFirst().invoke(request, response);
    }
}

执行一些判断是否有权限访问WEB-INF或者META-INF文件夹下的资源,确认请求等操作。接着往下调用Wrapper对应管道的阈。

1.7 StandardWrapperValve

其关键源码如下:

final class StandardWrapperValve extends ValveBase {
    protected Container container = null;
    protected Valve next = null;
    @Override
    public final void invoke(Request request, Response response)
        throws IOException, ServletException {
        // 初始化本地方法可能会用到的参数
        boolean unavailable = false;
        Throwable throwable = null;
        requestCount.incrementAndGet();
        StandardWrapper wrapper = (StandardWrapper) getContainer();
        Servlet servlet = null;
        Context context = (Context) wrapper.getParent();
        // 检查标记为不可用的应用程序
        if (!context.getState().isAvailable()) {
            ...
        }
        // servlet被标记为不可用
        if (!unavailable && wrapper.isUnavailable()) {
            ...
        }
        // 分配一个servlet实例来处理请求
        try {
            if (!unavailable) {
                // allocate实际上会调用StandardWrapper的initServlet方法
                // 去实例化一个Servlet,并调用Servlet的init方法。
                servlet = wrapper.allocate();
            }
        } catch (Throwable e) {
            ...
        }
        ...
        // 为此请求创建过滤器链
        ApplicationFilterChain filterChain = ApplicationFilterFactory
                .createFilterChain(request, wrapper, servlet);
        // 为此请求调用过滤器链
        Container container = this.container;
        try {
            if ((servlet != null) && (filterChain != null)) {
                if (context.getSwallowOutput()) {
                    try {
                        SystemLogHandler.startCapture();
                        if (request.isAsyncDispatching()) {
                            request.getAsyncContextInternal()
                                    .doInternalDispatch();
                        } else {
                            filterChain.doFilter(request.getRequest(),
                                    response.getResponse());
                        }
                    } finally {
                        String log = SystemLogHandler.stopCapture();
                        if (log != null && log.length() > 0) {
                            context.getLogger().info(log);
                        }
                    }
                } else {
                    if (request.isAsyncDispatching()) {
                        request.getAsyncContextInternal()
                                .doInternalDispatch();
                    } else {
                        filterChain.doFilter
                            (request.getRequest(), response.getResponse());
                    }
                }
            }
        } catch (Throwable e) {
            ...
        } finally {
            ...
        }
    }
}

可以看到这个阈中除了对request的请求进行校验外,还在其中初始化了StaddardWrapper封装的Servlet,并且从request中获得过滤器链并初始化,最后调用过滤器链。

1.8 ApplicationFilterChain

Servlet的过滤器链实在太多,因此我们只挑其中统筹兼顾的一个来进行分析。其关键源码如下:

public final class ApplicationFilterChain implements FilterChain {
    private static final ThreadLocal<ServletRequest> lastServicedRequest;
    private static final ThreadLocal<ServletResponse> lastServicedResponse;
    private Servlet servlet = null;
    // 当前读取的过滤器位置
    private int pos = 0;
    // 过滤器数量
    private int n = 0;
    @Override
    public void doFilter(ServletRequest request, ServletResponse response)
        throws IOException, ServletException {
        if( Globals.IS_SECURITY_ENABLED ) {
            // 可以忽略
            ...
        } else {
            internalDoFilter(request,response);
        }
    }
    private void internalDoFilter(ServletRequest request,
            ServletResponse response)
            throws IOException, ServletException {
        // 
        if (pos < n) {
            // 获得过滤器链中的过滤器
            ApplicationFilterConfig filterConfig = filters[pos++];
            try {
                Filter filter = filterConfig.getFilter();
                // 忽略
                ...
                if( Globals.IS_SECURITY_ENABLED ) {
                    // 忽略
                    ...
                } else {
                    // 调用过滤器链中的过滤器
                    filter.doFilter(request, response, this);
                }
            }  catch (Throwable e) {
                ...
            }
            return;
        }
    
        // 到这里代表前面的过滤器已经全部执行完毕,是时候该执行Servlet了
        try {
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                lastServicedRequest.set(request);
                lastServicedResponse.set(response);
            }
            if (request.isAsyncSupported() && !servletSupportsAsync) {
                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                        Boolean.FALSE);
            }
            // Use potentially wrapped request from this point
            if ((request instanceof HttpServletRequest) &&
                    (response instanceof HttpServletResponse) &&
                    Globals.IS_SECURITY_ENABLED ) {
                // 忽略
                ...
            } else {
                // 执行Servlet的service方法
                servlet.service(request, response);
            }
        }  catch (Throwable e) {
            ...
        } finally {
            if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
                lastServicedRequest.set(null);
                lastServicedResponse.set(null);
            }
        }
    }
}

 暂且把这个调用其它过滤器的类交模板过滤器,在这个过滤器关键方法中可以分成两部分,一部分是前面的调用各个过滤器逻辑,一个则是后续调用Servlet的逻辑。调用到过滤器和servlet后便无需多言了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值