Tomcat 8 源码学习七之请求如何从Tomcat到我们的SpringMVC
Contents
一次请求的调用栈
从上面的线程调用栈,可以看到一次请求的调用过程.
注意中间那些以Valve
结尾的类,它是Tomcat的里的责任链的组件.每一个组件,在Tomcat里都有自己对请求时可以进行自定义的处理.比如AccessLogValve
就是记录访问日志的Valve
.Tomcat自带的Valve,可以在包org.apache.catalina.valves
下可以看到所有的列表.
测试代码
HelloServlet
package com.example;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by sky on 16-6-30.
*/
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("hello world");
resp.getWriter().flush();
resp.getWriter().close();
}
}
web.xml
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1"
metadata-complete="true">
<display-name>Welcome to Tomcat</display-name>
<description>
Welcome to Tomcat
</description>
<servlet>
<servlet-name>hello-servlet</servlet-name>
<servlet-class>com.example.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>hello-servlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>
解析HTTP协议
Tomcat8默认使用 NIO 来处理HTTP了.看调用栈,可以知道,它通过org.apache.coyote.http11.AbstractInputBuffer.parseRequestLine()
来解析请求头的.
请求头的内容,保存在以下这个字段里.
/**
* Pointer to the current read buffer.
*/
protected byte[] buf;
解析完成后,就创建了一个org.apache.catalina.connector.Request
对象.
调用相应的责任链
通过Requset对象,再查找相应的Servlet(应该说是调用链,在Tomcat里,它用StandardWrapper
对象表示, 在这里就是hello-servlet
)(代码是 StandardWrapper wrapper = (StandardWrapper) getContainer();
)
最后,Tomcat就会调用名为hello-servlet
的Servlet来执行代码了.
Tomcat到SpringMVC
上面就已经执行到了我们自定义的hello-servlet
了,只要将这个Servlet,替换成Spring的org.springframework.web.servlet.DispatcherServlet
即可.它是SpringMVC的总控制及转发器(路由器,因为SpringMVC并不是使用传统的Servlet来对应每一个请求,而是使用Bean的某个方法来处理).