Tomcat源码版本:apache-tomcat-8.5.54-src
JDK源码版本:jdk1.8.0_171
一、请求流程关键代码
public class CoyoteAdapter implements Adapter {
...
@Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
throws Exception {
...
connector.getService() //StandardService
.getContainer() //StandardEngine
.getPipeline() //StandardPipeline
.getFirst() //StandardEngineValve
.invoke(request, response);
...
}
}
final class StandardEngineValve extends ValveBase {
...
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
Host host = request.getHost();
....
host //StandardHost
.getPipeline() //StandardPipeline
.getFirst() //AccessLogValve、ErrorReportValve、StandardHostValve
.invoke(request, response);
}
...
}
final class StandardHostValve extends ValveBase {
public final void invoke(Request request, Response response)
throws IOException, ServletException {
Context context = request.getContext();
....
try {
context.bind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) {
return;
}
try {
if (!response.isErrorReportRequired()) {
context //StandardContext
.getPipeline() //StandardPipeline
.getFirst() //AuthenticatorBase、StandardContextValve
.invoke(request, response);
}
} catch (Throwable t) {
...
}
...
if (!request.isAsync() && !asyncAtStart) {
context.fireRequestDestroyEvent(request.getRequest());
}
} finally {
....
context.unbind(Globals.IS_SECURITY_ENABLED, MY_CLASSLOADER);
}
}
...
}
final class StandardContextValve extends ValveBase {
...
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
...
Wrapper wrapper = request.getWrapper();
...
wrapper //StandardWrapper
.getPipeline() //StandardPipeline
.getFirst() //StandardWrapperValve
.invoke(request, response);
}
}
final class StandardWrapperValve extends ValveBase {
...
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
...
StandardWrapper wrapper = (StandardWrapper) getContainer();
Servlet servlet = null;
Context context = (Context) wrapper.getParent();
...
// Allocate a servlet instance to process this request
try {
if (!unavailable) {
//调用StandardWrapper的allocate的方法来获得一个servlet实例
servlet = wrapper.allocate();
}
} catch (UnavailableException e) {
...
} catch (ServletException e) {
...
} catch (Throwable e) {
...
}
...
//调用它的 private createFilterChain 方法获得过滤链
ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
// Call the filter chain for this request
// NOTE: This also calls the servlet's service() method
try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) {
request.getAsyncContextInternal().doInternalDispatch();
} else {
//调用过滤器链的 doFilter 方法。 包括调用 servlet 的 service方法
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 {
//最终会调用Servlet的service方法
filterChain.doFilter(request.getRequest(), response.getResponse());
}
}
}
} catch (ClientAbortException | CloseNowException e) {
...
} catch (IOException e) {
...
} catch (UnavailableException e) {
...
} catch (ServletException e) {
...
} catch (Throwable e) {
...
} finally {
// Release the filter chain (if any) for this request
if (filterChain != null) {
filterChain.release();
}
// Deallocate the allocated servlet instance
try {
if (servlet != null) {
wrapper.deallocate(servlet);
}
} catch (Throwable e) {
...
}
// If this servlet has been marked permanently unavailable,
// unload it and release this instance
try {
if ((servlet != null) &&
(wrapper.getAvailable() == Long.MAX_VALUE)) {
wrapper.unload();
}
} catch (Throwable e) {
...
}
...
}
}
}
//加载Servlet
public class StandardWrapper extends ContainerBase implements ServletConfig, Wrapper, NotificationEmitter {
@Override
public Servlet allocate() throws ServletException {
...
// If not SingleThreadedModel, return the same instance every time
if (!singleThreadModel) {
// Load and initialize our instance if necessary
if (instance == null || !instanceInitialized) {
synchronized (this) {
if (instance == null) {
try {
if (log.isDebugEnabled()) {
log.debug("Allocating non-STM instance");
}
instance = loadServlet();//加载Servelt
newInstance = true;
if (!singleThreadModel) {
countAllocated.incrementAndGet();
}
} catch (ServletException e) {
...
} catch (Throwable e) {
...
}
}
if (!instanceInitialized) {
initServlet(instance);//调用Servlet初始化方法
}
}
}
...
}
synchronized (instancePool) {
while (countAllocated.get() >= nInstances) {
if (nInstances < maxInstances) {
try {
instancePool.push(loadServlet());
nInstances++;
} catch (ServletException e) {
throw e;
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("standardWrapper.allocate"), e);
}
} else {
try {
instancePool.wait();
} catch (InterruptedException e) {
}
}
}
if (log.isTraceEnabled()) {
log.trace(" Returning allocated STM instance");
}
countAllocated.incrementAndGet();
return instancePool.pop();
}
}
public synchronized Servlet loadServlet() throws ServletException {
...
Servlet servlet;
try {
....
InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager();
try {
servlet = (Servlet) instanceManager.newInstance(servletClass);//根据全限定名将Servlet实例化
} catch (ClassCastException e) {
...
} catch (Throwable e) {
...
}
...
initServlet(servlet);//调用Servlet初始化方法
fireContainerEvent("load", this);
loadTime=System.currentTimeMillis() -t1;
} finally {
...
}
return servlet;
}
private synchronized void initServlet(Servlet servlet) throws ServletException {
...
try {
if( Globals.IS_SECURITY_ENABLED) {
boolean success = false;
try {
Object[] args = new Object[] { facade };
SecurityUtil.doAsPrivilege("init",
servlet,
classType,
args);
success = true;
} finally {
if (!success) {
// destroy() will not be called, thus clear the reference now
SecurityUtil.remove(servlet);
}
}
} else {
servlet.init(facade);//调用servlet init方法 传递封装的请求对象
}
instanceInitialized = true;
} catch (UnavailableException f) {
...
} catch (ServletException f) {
...
} catch (Throwable f) {
...
}
}
}
//调用链 最终执行Servlet的Service方法
public final class ApplicationFilterChain implements FilterChain {
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
try {
java.security.AccessController.doPrivileged(
new java.security.PrivilegedExceptionAction<Void>() {
@Override
public Void run()
throws ServletException, IOException {
internalDoFilter(req,res);
return null;
}
}
);
} catch( PrivilegedActionException pe) {
...
}
} 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 (request.isAsyncSupported() && "false".equalsIgnoreCase(
filterConfig.getFilterDef().getAsyncSupported())) {
request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
}
if( Globals.IS_SECURITY_ENABLED ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res, this};
SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
} else {
filter.doFilter(request, response, this);
}
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}
// We fell off the end of the chain -- call the servlet instance
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 ) {
final ServletRequest req = request;
final ServletResponse res = response;
Principal principal =
((HttpServletRequest) req).getUserPrincipal();
Object[] args = new Object[]{req, res};
SecurityUtil.doAsPrivilege("service",
servlet,
classTypeUsedInService,
args,
principal);
} else {
servlet.service(request, response);//执行Servlet的Service方法
}
} catch (IOException | ServletException | RuntimeException e) {
...
} catch (Throwable e) {
...
} finally {
...
}
}
}
Servlet执行结束之后的逻辑:
public class CoyoteAdapter implements Adapter {
@Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
throws Exception {
....
try {
postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
//check valves if we support async
request.setAsyncSupported(
connector.getService().getContainer().getPipeline().isAsyncSupported());
// Calling the container
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);//Servlet调用链
}
if (request.isAsync()) {
...
} else {
//执行以下两个方法 就会将输出信息刷到浏览器进行渲染
request.finishRequest();
response.finishResponse();
}
} catch (IOException e) {
} finally {
....
// 记录访问日志
if (!async && postParseSuccess) {
Context context = request.getContext();
Host host = request.getHost();
long time = System.currentTimeMillis() - req.getStartTime();
if (context != null) {
context.logAccess(request, response, time, false);
} else if (response.isError()) {
if (host != null) {
host.logAccess(request, response, time, false);
} else {
connector.getService().getContainer().logAccess(
request, response, time, false);
}
}
}
req.getRequestProcessor().setWorkerThreadName(null);
...
}
}
...
}
二、测试Demo
1、 Demo目录;
2、 关键代码;
servlet:
package com.test;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HelloWorld extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.err.println("HelloWorld doGet");
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.err.println("HelloWorld doPost");
String name = request.getParameter("name"); //获取jsp页面传过来的参数
String pwd = request.getParameter("pwd");
String sex = request.getParameter("sex");
String home = request.getParameter("home");
String info = request.getParameter("info");
//request.setAttribute("username", name); //向request域中放置参数
//request.getRequestDispatcher("/denglu.jsp").forward(request, response); //转发到登录页面
response.sendRedirect("hello.jsp");//重定向到首页
}
}
package com.test;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class Index implements Servlet{
@Override
public void init(ServletConfig paramServletConfig) throws ServletException {
System.out.println("Index Servlet init");
}
@Override
public void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)
throws ServletException, IOException {
System.out.println("Index Servlet service");
HttpServletResponse res = (HttpServletResponse)paramServletResponse;
res.sendRedirect("index.jsp");//重定向到首页
}
@Override
public ServletConfig getServletConfig() {
System.out.println("Index Servlet getServletConfig");
return null;
}
@Override
public String getServletInfo() {
System.out.println("Index Servlet getServletInfo");
return null;
}
@Override
public void destroy() {
System.out.println("Index Servlet destroy");
}
}
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<display-name>WebDemo</display-name>
<servlet>
<servlet-name>index</servlet-name>
<servlet-class>com.test.Index</servlet-class>
</servlet>
<servlet>
<servlet-name>hello</servlet-name>
<servlet-class>com.test.HelloWorld</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>index</servlet-name>
<url-pattern>/index</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>首页
</body>
</html>
3、 部署路径;
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
<Context docBase="E:\workspace\mot\WebDemo\web"
path="/WebDemo" reloadable="true" />
</Host>
</Engine>
</Service>
</Server>
4、 调试打印;
请求:http://localhost:8080/WebDemo/index
控制台输出:
Index Servlet init
Index Servlet service