美文网首页
Tomcat与SpringMVC如何协作完成一次Http请求?

Tomcat与SpringMVC如何协作完成一次Http请求?

作者: 王侦 | 来源:发表于2023-03-05 11:17 被阅读0次

    1.Tomcat Connector接收请求

    线程池中线程TaskThread#run进行处理(http-nio线程):

    • SocketProcessorBase#run(是个Runnable任务)
    • NioEndpoint.SocketProcessor#doRun
    • AbstractProtocol.ConnectionHandler#process
    • AbstractProcessorLight#process
    • Http11Processor#service
    • CoyoteAdapter#service

    Acceptor

    Acceptor#run()

    • LimitLatch限制客户端连接总数,默认是8*1024
    • socket = endpoint.accept()
    • 创建NioChannel,并设置为非阻塞,然后poller.register(socketWrapper);

    AbstractEndpoint#startAcceptorThread

    • Acceptor线程只有一个

    Poller

    NioEndpoint.Poller#register

    • socketWrapper关注SelectionKey.OP_READ
    • 新建PollerEvent(OP_REGISTER),放到events队列中(SynchronizedQueue)

    NioEndpoint.Poller#run

    • events(),这里从队列events取出事件,如果是注册,则向selector注册OP_READ事件
    • 然后调用selector.select(selectorTimeout)
    • 如果有读写事件,则遍历SelectionKey进行处理processKey(sk, socketWrapper)
    • 创建SocketProcessor,事件类型是SocketEvent.OPEN_READ,获取线程池,丢到线程池执行executor.execute(sc);

    NioEndpoint#startInternal

    • poller = new Poller();该线程也只有一

    Executor执行线程池

    NioEndpoint#startInternal

    • AbstractEndpoint#createExecutor
    • 线程池数量默认最小是10,最大是200
        public void createExecutor() {
            internalExecutor = true;
            TaskQueue taskqueue = new TaskQueue();
            TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
            executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
            taskqueue.setParent( (ThreadPoolExecutor) executor);
        }
    

    SocketProcessor

    NioEndpoint.SocketProcessor#doRun

    • getHandler().process(socketWrapper, event)
    • 这里的handler是在AbstractHttp11Protocol构造方法里面创建的ConnectionHandler
    • processor.process(wrapper, status);这里processor是Http11Processor

    Http11Processor

    Http11Processor#process

    • AbstractProcessorLight#process
    • Http11Processor#service
    • 最终CoyoteAdapter#service

    2.Tomcat 多级容器处理

    Request中MappingData

    CoyoteAdapter#service

    • CoyoteAdapter#postParseRequest(处理完这个,然后才调用容器的pipeline)
    • Mapper#map()
    • Mapper#internalMap,此时入参
      host:localhost
      uri:/order-service/order/add

    核心就在Mapper#internalMap,在此进行匹配:

    • 1)MappedHost mappedHost = exactFindIgnoreCase(hosts, host);在Mapper.hosts里面匹配host(localhost)
    • 2)find(contexts, uri);在匹配的mappedHost.contextList.contexts中匹配uri(/order-service/order/add)
    • 3)internalMapWrapper(contextVersion, uri, mappingData);匹配Wrapper
      A)Rule 1 -- Exact Match
      B)Rule 2 -- Prefix Match
      C)Rule 3 -- Extension Match
      D)Rule 4 -- Welcome resources processing for servlets
      E)Rule 7 -- Default servlet

    容器pipeline调用

    CoyoteAdapter#service

    • StandardEngineValve#invoke
    • StandardHostValve#invoke
    • StandardContextValve#invoke
    • StandardWrapperValve#invoke
    • ApplicationFilterChain#doFilter

    3.过滤器处理

    ApplicationFilterChain#doFilter

    • OncePerRequestFilter#doFilter
    • CharacterEncodingFilter#doFilterInternal
    • FormContentFilter#doFilterInternal
    • RequestContextFilter#doFilterInternal
    • WsFilter#doFilter

    4.Servlet处理(SpringMVC的DispatcherServlet的处理)

    过滤器结束后:

    • ApplicationFilterChain#internalDoFilter
    • HttpServlet#service(),这里实际是DispatcherServlet
    • DispatcherServlet#doDispatch

    SpringMVC和Tomcat的结合点是Servlet。

    Springmvc的核心是一个DispatcherServlet,负责请求的解析,拦截,转发,响应等等。

    DispatchServlet实现了HttpServlet,那么SpringMVC在Tomcat看来,其实就是一个Servlet。所有的http请求都是映射到这个DispatchServlet上,请求进入到DispatchServlet中之后,就算进入到了框架之中了,由这个Servlet来统一的分配http请求到各个Controller。

    5.整体流程总结

    整体流程:

    • 1)Acceptor接收客户端连接请求
    • 2)Poller接收客户端读写请求
    • 3)Executor执行SocketProcessor任务
    • 4)Http11Processor处理Http请求
    • 5)CoyoteAdapter首先进行host/context/wrapper匹配,放到Request的MappingData中
    • 6)各级容器Pipeline的阀门处理
    • 7)ApplicationFilterChain过滤器链处理
    • 8)DispatcherServlet进行处理(如下为SpringMVC处理流程)
    • 9)会从三个HandlerMapping(this.handlerMappings)根据request查找Handler,并找出对应拦截器组成HandlerExecutionChain
    • 10)拿到对应的Handler后,会转换为HandlerAdapter
    • 11)mappedHandler#applyPreHandle 拦截器前置方法
    • 12)HandlerAdapter#handle
       A)参数解析RequestParamMethodArgumentResolver#resolveName
       B)参数类型转换:String -> User,可以定义类型转换器PropertyEditorSupport,然后@InitBinder,注册User -> PropertyEditorSupport)
       C)doInvoke(args)调用我们定义的目标方法
       D)messageConverter进行类型转换
       E)返回值解析器处理返回值
    • 13)mappedHandler.applyPostHandle 拦截器后置方法
    • 14)processDispatchResult()渲染视图,执行拦截器afterCompletion方法

    相关文章

      网友评论

          本文标题:Tomcat与SpringMVC如何协作完成一次Http请求?

          本文链接:https://www.haomeiwen.com/subject/poiyldtx.html