以NIO为例
1. NioEndpoint.Acceptor 阻塞处理 accept() 并把合适的socket 放置BlockingQueue
2. NioEndpoint.Poller 从BlockingQueue拿socket,使用NIO的非阻塞方式 处理read(),把read()事件ready的socket交给线程池处理
3. read() http请求内容并包装request
4. 以request 的具体请求path 分别找到匹配的 host context wrapper(在没有配置load-on-startup时内含的servlet instance第一次访问时是null)
5. 分别从匹配的host context wrapper中拿出相应的处理流程 hostvalve contextvalve wrappervalve 依次去处理
6. wrappervalve这一步中需要先把servlet实例化(在还没有被实例化的情况下)
7. 找到request path匹配的所有filter+servlet 组成filterChain 然后调用filterChain
8. 在所有的filter的doFilter() 跑完后 调用servlet 的service()
9. 返回结果写回 socket
JSP流程
主体流程与以上一样,有意思的是处理JSP的是的step 4是中的wrapper持有的instance是固定的JspServlet。主要说说JspServlet.Service()方法的流程
假使访问流程如下:
1)访问JSP
2)修改JSP
3)再次访问JSP(以下展示此次流程)
1. 正如servlet的路由表value是使用wrapper(StandardWrapper)来做包装,同样在JspServlet中的路由表也不是直接指向JSP的实例对象,也是类似的wrapper(JspServletWrapper)
2. 通过url找到对应的JspServletWrapper
3. JspServletWrapper中会经过:尝试编译,获取实例,调用JSP编译后的class文件的_jspService()方法
1). 查看是否打开JSP动态编译||是否第一次加载JSP。如果是则首先检测该JSP有没有修改。如果有,则使用JDTCompiler编译JSP为class。
2). 调用原先的JSP对应servlet的destroy()方法
3). 如果1 中进行过重新编译,则需要使用新的classloader去加载JSP对应的class文件并进行实例化,最后把JspServletWrapper的theServlet赋值为最新的实例
4). 调用JSP对应class文件的_jspService()方法