概述

tomcat的核心就是处理请求, 接收Request, 建立Socket链接, 处理,返回Response。 通过前面的架构图可以知道每个Service都包括连接器Connector组件和容器Container组件。 我们就从Connector组件开始分析。 在分析tomcat是如何处理请求前我们首先要进一步分析下tomcat初始化都做了那些事情。

这里加一个承上启下, 说明下Server和Service的关系, 在StandardServer的初始化Service, Service中去初始化Connector。

分析Server.xml

<!-- A "Connector" represents an endpoint by which requests are received
         and responses are returned. Documentation at :
         Java HTTP Connector: /docs/config/http.html
         Java AJP  Connector: /docs/config/ajp.html
         APR (HTTP/AJP) Connector: /docs/apr.html
         Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
    -->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

以上Server.xml代码片段, 我们能得到结论,Connector组件有三种类型组件:

  • HTTP Connector, 也是我们用到最多的场景, 表示一个处理HTTP/1.1协议的组件,负责建立HTTP连接,其中又分为BIO Http Connector和NIO Http Connecotr。
  • AJP Connector, AJP协议,全名Apache JServ Protocol,采用二进制格式传输可读文本,是专门设计用于Tomcat和HTTP服务器通信定制的协议,能够提供较高的通信效率和速率。
  • APR Connector,用C实现,通过JNI调用的。主要提升对静态资源(如HTML、图片、CSS、JS等)的访问性能

Connector类的初始化过程

要看Connector类的初始化过程,我们还得从Catalina类开始分析。 那么开始分析之前,我们先做个猜测,整个tomcat是如何处理请求的, 我们知道初始化的过程肯定是要建立一个ServerSocket用来处理客户端过来的请求,我们带着这个问题去分析。
通过前面的分析,我们知道这几个核心组件都实现了LifeCycle接口, 这个接口会自己实现init,start, stop类似方法,然后通过钩子(Hook)的方法声明internal方法给实现类或者子类去实现和调用, 比如这里的initInternal。

Connector类初始化调用链

Catalina#load

public void load() {
	if (loaded) {
		return;
	}
	
	loaded = true;
	long t1 = System.nanoTime();
	initDirs();
	initNaming();
	Digester digester = createStartDigester();

	InputSource inputSource = null;
	InputStream inputStream = null;
	File file = null;
	try {
		try {
			file = configFile();
			inputStream = new FileInputStream(file);
			inputSource = new InputSource(file.toURI().toURL().toString());
		} catch (Exception e) {
			
		}
		if (inputStream == null) {
			try {
				inputStream = getClass().getClassLoader()
					.getResourceAsStream(getConfigFile());
				inputSource = new InputSource
					(getClass().getClassLoader()
					 .getResource(getConfigFile()).toString());
			} catch (Exception e) {
				
			}
		}

		if (inputStream == null) {
			try {
				inputStream = getClass().getClassLoader()
						.getResourceAsStream("server-embed.xml");
				inputSource = new InputSource
				(getClass().getClassLoader()
						.getResource("server-embed.xml").toString());
			} catch (Exception e) {
				
			}
		}


		if (inputStream == null || inputSource == null) {
			return;
		}

		try {
			inputSource.setByteStream(inputStream);
			digester.push(this);
			digester.parse(inputSource);
		} catch (SAXParseException spe) {
			
			return;
		} catch (Exception e) {
			
			return;
		}
	} finally {
		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (IOException e) {
				
			}
		}
	}

	getServer().setCatalina(this);
	getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
	getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());

	initStreams();

	try {
        //这里也就是调用StandardServer.init方法
		getServer().init();
	} catch (LifecycleException e) {
		
	}
}

StandardServer#initInternal

protected void initInternal() throws LifecycleException {
	super.initInternal();

	onameStringCache = register(new StringCache(), "type=StringCache");

	MBeanFactory factory = new MBeanFactory();
	factory.setContainer(this);
	onameMBeanFactory = register(factory, "type=MBeanFactory");

	globalNamingResources.init();

	if (getCatalina() != null) {
		ClassLoader cl = getCatalina().getParentClassLoader();

		while (cl != null && cl != ClassLoader.getSystemClassLoader()) {
			if (cl instanceof URLClassLoader) {
				URL[] urls = ((URLClassLoader) cl).getURLs();
				for (URL url : urls) {
					if (url.getProtocol().equals("file")) {
						try {
							File f = new File (url.toURI());
							if (f.isFile() && f.getName().endsWith(".jar")) {
								ExtensionValidator.addSystemResource(f);
							}
						} catch (URISyntaxException | IOException e) {
							
						}
					}
				}
			}
			cl = cl.getParent();
		}
	}
	
	for (Service service : services) {
		service.init();
	}
}

StandardService#initInternal

protected void initInternal() throws LifecycleException {
	super.initInternal();

	if (engine != null) {
		engine.init();
	}

	for (Executor executor : findExecutors()) {
		if (executor instanceof JmxEnabled) {
			((JmxEnabled) executor).setDomain(getDomain());
		}
		executor.init();
	}

	mapperListener.init();

	synchronized (connectorsLock) {
        //这里开始调用Connector.init方法
		for (Connector connector : connectors) {
			try {
				connector.init();
			} catch (Exception e) {
				
			}
		}
	}
}

Connector构造函数

public void setProtocol(String protocol) {
	boolean aprConnector = AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseAprConnector();
	
	if ("HTTP/1.1".equals(protocol) || protocol == null) {
		if (aprConnector) {
			setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
		} else {
			setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
		}
	} else if ("AJP/1.3".equals(protocol)) {
		if (aprConnector) {
			setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
		} else {
			setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
		}
	} else {
		setProtocolHandlerClassName(protocol);
	}
}

public Connector(String protocol) {
	setProtocol(protocol);
	// Instantiate protocol handler
	ProtocolHandler p = null;
	try {
		Class<?> clazz = Class.forName(protocolHandlerClassName);
		//通过反射方式构造ProtocolHandler实例, 也就是构造Http11NioProtocol类实例
		p = (ProtocolHandler) clazz.getConstructor().newInstance();
	} catch (Exception e) {
		
	} finally {
		this.protocolHandler = p;
	}

	if (Globals.STRICT_SERVLET_COMPLIANCE) {
		uriCharset = StandardCharsets.ISO_8859_1;
	} else {
		uriCharset = StandardCharsets.UTF_8;
	}

	if (Boolean.parseBoolean(System.getProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "false"))) {
		encodedSolidusHandling = EncodedSolidusHandling.DECODE;
	}
}

Connector#init

protected void initInternal() throws LifecycleException {
	super.initInternal();
	
	//CoyoteAdapter是连接器转发的一个组件,把request对象转换成ServletRequest对象 (适配器的设计模式)
	adapter = new CoyoteAdapter(this);
	protocolHandler.setAdapter(adapter);

	if (null == parseBodyMethodsSet) {
		setParseBodyMethods(getParseBodyMethods());
	}

	if (protocolHandler.isAprRequired() && !AprLifecycleListener.isInstanceCreated()) {
		throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener",
				getProtocolHandlerClassName()));
	}
	if (protocolHandler.isAprRequired() && !AprLifecycleListener.isAprAvailable()) {
		throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary",
				getProtocolHandlerClassName()));
	}
	if (AprLifecycleListener.isAprAvailable() && AprLifecycleListener.getUseOpenSSL() &&
			protocolHandler instanceof AbstractHttp11JsseProtocol) {
		AbstractHttp11JsseProtocol<?> jsseProtocolHandler =
				(AbstractHttp11JsseProtocol<?>) protocolHandler;
		if (jsseProtocolHandler.isSSLEnabled() && jsseProtocolHandler.getSslImplementationName() == null) {
			jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName());
		}
	}

	try {
	    //ProtocolHandler初始化 - 也就是调用Http11NioProtocol初始化
		protocolHandler.init();
	} catch (Exception e) {
		
	}
}

AbstractProtocol#init

这个类里也就看到了endpoint属性, endpoint是AbstractEndpoint类型。

public void init() throws Exception {
	if (getLog().isInfoEnabled()) {
		logPortOffset();
	}

	if (oname == null) {
		oname = createObjectName();
		if (oname != null) {
			Registry.getRegistry(null, null).registerComponent(this, oname, null);
		}
	}

	if (this.domain != null) {
		ObjectName rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
		this.rgOname = rgOname;
		Registry.getRegistry(null, null).registerComponent(getHandler().getGlobal(), rgOname, null);
	}

    //设置endpoint名字,默认为http-nio-{port}
	String endpointName = getName();
	endpoint.setName(endpointName.substring(1, endpointName.length()-1));
	endpoint.setDomain(domain);
    //调用endpoint初始化方法
	endpoint.init();
}

AbstractEndpoint#init

public void init() throws Exception {
	if (bindOnInit) {
	   bindWithCleanup();
	   bindState = BindState.BOUND_ON_INIT;
	}
	
	if (this.domain != null) {
	   oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
	   Registry.getRegistry(null, null).registerComponent(this, oname, null);

	   ObjectName socketPropertiesOname = new ObjectName(domain + ":type=SocketProperties,name=\"" + getName() + "\"");
	   socketProperties.setObjectName(socketPropertiesOname);
	   Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null);

	   for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
		 registerJmx(sslHostConfig);
	   }
	}
}

AbstractEndpoint#bindWithCleanUp

bindWithCleanUp又调用了bind方法, bind方法是父类预留的一个抽象方法, 方法在最终实现类里去重写, 而AbstractEndpoint的最终实现类是NioEndpoint类, 也就是这里最终会调用NioEndpoint#bind方法。

private void bindWithCleanup() throws Exception {
    try {
        bind();
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        unbind();
        throw t;
    }
}

NioEndpoint#bind

public void bind() throws Exception {
	initServerSocket();
	setStopLatch(new CountDownLatch(1));
	initialiseSsl();
}

NioEndpoint#initServerSocket

protected void initServerSocket() throws Exception {
    if (getUseInheritedChannel()) {
        Channel ic = System.inheritedChannel();
        if (ic instanceof ServerSocketChannel) {
            serverSock = (ServerSocketChannel) ic;
        }
        if (serverSock == null) {
            throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
        }
    } else {
        serverSock = ServerSocketChannel.open();
        socketProperties.setProperties(serverSock.socket());
        //绑定8080端口
        InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
        serverSock.socket().bind(addr,getAcceptCount());
    }
    serverSock.configureBlocking(true);
}

tomcat源码分析(二)如何处理请求-小白菜博客
找到了这一步,才算看到了核心内容,声明ServerSocketChannel, 绑定8080端口, 初始化只是监听了端口,这里需要调用start方法来接收客户发送来的请求。 我们按照相同的调用链,在NioEndpoint里找到了startInternal方法。

tomcat接收请求-处理请求

NioEndpoint#startInternal

/***
  开启Endpoint, 创建acceptor, poller线程
***/
public void startInternal() throws Exception {
	if (!running) {
		running = true;
		paused = false;

		if (socketProperties.getProcessorCache() != 0) {
			processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE, socketProperties.getProcessorCache());
		}
		if (socketProperties.getEventCache() != 0) {
			eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE, socketProperties.getEventCache());
		}
		if (socketProperties.getBufferPool() != 0) {
			nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE, socketProperties.getBufferPool());
		}

		// 创建线程池
		if (getExecutor() == null) {
			createExecutor();
		}

		initializeConnectionLatch();

		//开启poller线程
		poller = new Poller();
        //poller线程name:http-nio-{port}-Poller
		Thread pollerThread = new Thread(poller, getName() + "-Poller");
		pollerThread.setPriority(threadPriority);
		pollerThread.setDaemon(true);
		pollerThread.start();

		startAcceptorThread();
	}
}

AbstractEndpoint#startAcceptorThread

protected void startAcceptorThread() {
    acceptor = new Acceptor<>(this);
    //acceptor线程name:http-nio-{port}-Acceptor
    String threadName = getName() + "-Acceptor";
    acceptor.setThreadName(threadName);
    Thread t = new Thread(acceptor, threadName);
    t.setPriority(getAcceptorThreadPriority());
    t.setDaemon(getDaemon());
    t.start();
}
public class Acceptor<U> implements Runnable {
    
}

public class Poller implements Runnable {
    
}

这里又带出来两个概念:Poller,Acceptor, Poller类是NioEndpoint的一个内部类,实现了Runnable接口,Acceptor类是一个独立类,放在org.apache.tomcat.util.net包下,也实现了Runnable接口,所以这两个类都是线程相关, 这两个类在接收请求和处理请求的过程中起了承上启下的作用。 这里我们通过三张图来看看他们是怎么工作的。

截图一

poller2222.png

  • Acceptor 线程, 用于接收Socket,并包装NioChannel对象,再封装成PollerEvent对象,压入到events queue队列中。
  • Poller线程,监听Socket事件, 取出PollerEvent对象并且交给Work线程池。
  • Work线程,用于处理请求。

截图二

Acceptor.png

截图三

Poller.png

Poller#run

public void run() {
	while (true) {
		boolean hasEvents = false;
		try {
			if (!close) {
				hasEvents = events();
				if (wakeupCounter.getAndSet(-1) > 0) {
					keyCount = selector.selectNow();
				} else {
					keyCount = selector.select(selectorTimeout);
				}
				wakeupCounter.set(0);
			}
			if (close) {
				events();
				timeout(0, false);
				try {
					selector.close();
				} catch (IOException ioe) {
					log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
				}
				break;
			}
			
			if (keyCount == 0) {
				hasEvents = (hasEvents | events());
			}
		} catch (Throwable x) {
			ExceptionUtils.handleThrowable(x);
			continue;
		}

		Iterator<SelectionKey> iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null;
		
		while (iterator != null && iterator.hasNext()) {
			SelectionKey sk = iterator.next();
			iterator.remove();
			NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
			
			if (socketWrapper != null) {
				processKey(sk, socketWrapper);
			}
		}

		timeout(keyCount,hasEvents);
	}

	getStopLatch().countDown();
}

NioEndpoint#processKey

protected void processKey(SelectionKey sk, NioSocketWrapper socketWrapper) {
	try {
		if (close) {
			cancelledKey(sk, socketWrapper);
		} else if (sk.isValid()) {
			if (sk.isReadable() || sk.isWritable()) {
				if (socketWrapper.getSendfileData() != null) {
					processSendfile(sk, socketWrapper, false);
				} else {
					unreg(sk, socketWrapper, sk.readyOps());
					boolean closeSocket = false;
				
					if (sk.isReadable()) {
						if (socketWrapper.readOperation != null) {
							if (!socketWrapper.readOperation.process()) {
								closeSocket = true;
							}
						} else if (socketWrapper.readBlocking) {
							synchronized (socketWrapper.readLock) {
								socketWrapper.readBlocking = false;
								socketWrapper.readLock.notify();
							}
						} else if (!processSocket(socketWrapper, SocketEvent.OPEN_READ, true)) {
							closeSocket = true;
						}
					}
					if (!closeSocket && sk.isWritable()) {
						if (socketWrapper.writeOperation != null) {
							if (!socketWrapper.writeOperation.process()) {
								closeSocket = true;
							}
						} else if (socketWrapper.writeBlocking) {
							synchronized (socketWrapper.writeLock) {
								socketWrapper.writeBlocking = false;
								socketWrapper.writeLock.notify();
							}
						} else if (!processSocket(socketWrapper, SocketEvent.OPEN_WRITE, true)) {
							closeSocket = true;
						}
					}
					if (closeSocket) {
						cancelledKey(sk, socketWrapper);
					}
				}
			}
		} else {
			cancelledKey(sk, socketWrapper);
		}
	} catch (CancelledKeyException ckx) {
		cancelledKey(sk, socketWrapper);
	} catch (Throwable t) {
		ExceptionUtils.handleThrowable(t);
		log.error(sm.getString("endpoint.nio.keyProcessingError"), t);
	}
}

AbstractEndpoint#processSocket

public boolean processSocket(SocketWrapperBase<S> socketWrapper, SocketEvent event, boolean dispatch) {
	try {
		if (socketWrapper == null) {
			return false;
		}
		SocketProcessorBase<S> sc = null;
		if (processorCache != null) {
			sc = processorCache.pop();
		}
		if (sc == null) {
			sc = createSocketProcessor(socketWrapper, event);
		} else {
			sc.reset(socketWrapper, event);
		}
		Executor executor = getExecutor();
		if (dispatch && executor != null) {
            //这里把封装的SocketWrapperBase交给线程池去处理
            executor.execute(sc);
		} else {
			sc.run();
		}
	} catch (RejectedExecutionException ree) {
		return false;
	} catch (Throwable t) {
		ExceptionUtils.handleThrowable(t);
		return false;
	}
	return true;
}

SocketProcessorBase#run

SocketProcessorBase也实现了Runnable接口,也是一个线程类, 这里在run方法内调用抽象方法doRun,子类去重写这个方法。 我们还是在NioEndpoint类里找到了内部类SocketProcessor继承了抽象类SocketProcessBase。

 @Override
public final void run() {
    synchronized (socketWrapper) {
        if (socketWrapper.isClosed()) {
            return;
        }
        doRun();
    }
}


protected abstract void doRun();

SocketProcessor#doRun

在SocketProcessor类上可以看到注释说明,这个等效于Worker线程类,会在另一个线程池里去处理。

SocketState state = SocketState.OPEN;
// 从Socket里处理请求
if (event == null) {
    state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
} else {
    state = getHandler().process(socketWrapper, event);
}

这个代码片段里会调用handler#process方法去处理请求, Handler是AbstractEndpoint类内部的静态接口,只有一个实现类ConnectionHandler

ConnectionHandler#process

SocketState state = SocketState.CLOSED;
state = processor.process(wrapper, status);

这里processor变量类型是接口Processor,实现类AbstractProcessorLight。

AbstractProcessorLight#process

public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status) throws IOException {
	SocketState state = SocketState.CLOSED;
	Iterator<DispatchType> dispatches = null;
	do {
		if (dispatches != null) {
			DispatchType nextDispatch = dispatches.next();
			
			state = dispatch(nextDispatch.getSocketStatus());
			if (!dispatches.hasNext()) {
				state = checkForPipelinedData(state, socketWrapper);
			}
		} else if (status == SocketEvent.DISCONNECT) {
			
		} else if (isAsync() || isUpgrade() || state == SocketState.ASYNC_END) {
			state = dispatch(status);
			state = checkForPipelinedData(state, socketWrapper);
		} else if (status == SocketEvent.OPEN_WRITE) {
			state = SocketState.LONG;
		} else if (status == SocketEvent.OPEN_READ) {
			state = service(socketWrapper);
		} else if (status == SocketEvent.CONNECT_FAIL) {
			logAccess(socketWrapper);
		} else {
			state = SocketState.CLOSED;
		}

		if (isAsync()) {
			state = asyncPostProcess();
		}

		if (dispatches == null || !dispatches.hasNext()) {
			dispatches = getIteratorAndClearDispatches();
		}
	} while (state == SocketState.ASYNC_END || dispatches != null && state != SocketState.CLOSED);

	return state;
}

这个代码片段里里继续调用抽象方法service, 这里会进一步调用实现类Http11Processor#service。

AbstractProcessor#service

处理到这一步,才算看到了眼熟的request和response变量, service方法根据入参SocketWrapperBase去解析request和response变量。

//成员变量
protected final Request request;
protected final Response response;

//构造器
protected AbstractProcessor(AbstractEndpoint<?,?> endpoint, Request coyoteRequest, Response coyoteResponse) {
	this.endpoint = endpoint;
	asyncStateMachine = new AsyncStateMachine(this);
	request = coyoteRequest;
	response = coyoteResponse;
	response.setHook(this);
	request.setResponse(response);
	request.setHook(this);
	userDataHelper = new UserDataHelper(getLog());
}


//这里调用adapter.service方法处理请求
if (getErrorState().isIoAllowed()) {
	try {
		rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
        //这里去调用adapter.service方法。
		getAdapter().service(request, response);

		if(keepAlive && !getErrorState().isError() && !isAsync() && statusDropsConnection(response.getStatus())) {
			setErrorState(ErrorState.CLOSE_CLEAN, null);
		}
	} catch (InterruptedIOException e) {
		setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
	} catch (HeadersTooLargeException e) {
		if (response.isCommitted()) {
			setErrorState(ErrorState.CLOSE_NOW, e);
		} else {
			response.reset();
			response.setStatus(500);
			setErrorState(ErrorState.CLOSE_CLEAN, e);
			response.setHeader("Connection", "close");
		}
	} catch (Throwable t) {
		ExceptionUtils.handleThrowable(t);
		response.setStatus(500);
		setErrorState(ErrorState.CLOSE_CLEAN, t);
		getAdapter().log(request, response, 0);
	}
}

这里会调用getAdapter().service()去处理请求, adapter变量类型是接口Adapter, 他包含一个实现类CoyoteAdapter,也就是这里会继续向下调用CoyoteAdapter#service, 入参是request和response。

CoyoteAdapter#service

这个方法体比较长,其中最重要的一行代码我贴了出来,以防止看源码调用链时被其他逻辑干扰,这行代码上面写了一句关键注释,会去交给容器处理请求,也就是这里会进一步调用Valve接口的invoke方法, 这里会调用实现类StandardContextValve#invoke方法去处理请求。

// Calling the container
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);

StandardContextValve#invoke

public final void invoke(Request request, Response response) throws IOException, ServletException {
	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(ContinueResponseTiming.IMMEDIATELY);
	} catch (IOException ioe) {
		request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ioe);
		response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
		return;
	}

	if (request.isAsyncSupported()) {
		request.setAsyncSupported(wrapper.getPipeline().isAsyncSupported());
	}
	wrapper.getPipeline().getFirst().invoke(request, response);
}

这个方法体里又会进一步把请求要给wrapper相关类来处理,一样是转交给invoke方法去处理,不过这个层面会交给StandardWrapperValve#invoke方法去处理, 这个方法里有两处关键的逻辑,一是找到你请求的servlet,而是调用service方法去处理请求,也就是我们处理业务最后会写入Response里的内容。

StandardWrapperValve#invoke

public final void invoke(Request request, Response response) throws IOException, ServletException {
	boolean unavailable = false;
	Throwable throwable = null;
	
	long t1=System.currentTimeMillis();
	requestCount.incrementAndGet();
	StandardWrapper wrapper = (StandardWrapper) getContainer();
	//声明处理请求的servlet
	Servlet servlet = null;
	Context context = (Context) wrapper.getParent();

	if (!context.getState().isAvailable()) {
		response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,sm.getString("standardContext.isUnavailable"));
		unavailable = true;
	}

	if (!unavailable && wrapper.isUnavailable()) {
		container.getLogger().info(sm.getString("standardWrapper.isUnavailable", wrapper.getName()));
		checkWrapperAvailable(response, wrapper);
		unavailable = true;
	}

	// 重要,分配一个servlet去处理请求
	try {
		if (!unavailable) {
			servlet = wrapper.allocate();
		}
	} catch (UnavailableException e) {
		checkWrapperAvailable(response, wrapper);
	} catch (ServletException e) {
		throwable = e;
		exception(request, response, e);
	} catch (Throwable e) {
		ExceptionUtils.handleThrowable(e);
		throwable = e;
		exception(request, response, e);
		servlet = null;
	}

	MessageBytes requestPathMB = request.getRequestPathMB();
	DispatcherType dispatcherType = DispatcherType.REQUEST;
	if (request.getDispatcherType()==DispatcherType.ASYNC) {
		dispatcherType = DispatcherType.ASYNC;
	}
	request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType);
	request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,  requestPathMB);
	//为当前这个请求创建过滤器链
	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 {
					
				}
			} else {
				if (request.isAsyncDispatching()) {
					request.getAsyncContextInternal().doInternalDispatch();
				} else {
					filterChain.doFilter(request.getRequest(), response.getResponse());
				}
			}

		}
	} catch (ClientAbortException | CloseNowException e) {
		throwable = e;
		exception(request, response, e);
	} catch (IOException e) {
		throwable = e;
		exception(request, response, e);
	} catch (UnavailableException e) {
		wrapper.unavailable(e);
		checkWrapperAvailable(response, wrapper);
	} catch (ServletException e) {
		Throwable rootCause = StandardWrapper.getRootCause(e);
		throwable = e;
		exception(request, response, e);
	} catch (Throwable e) {
		ExceptionUtils.handleThrowable(e);
		throwable = e;
		exception(request, response, e);
	} finally {
		if (filterChain != null) {
			filterChain.release();
		}

		try {
			if (servlet != null) {
				wrapper.deallocate(servlet);
			}
		} catch (Throwable e) {
			ExceptionUtils.handleThrowable(e);
			container.getLogger().error(sm.getString("standardWrapper.deallocateException",
							 wrapper.getName()), e);
			if (throwable == null) {
				throwable = e;
				exception(request, response, e);
			}
		}
	}
}

这里我在本地源码创建一个servlet,去验证源码逻辑, 这里就能看到请求的HelloWorldServlet
tomcat源码分析(二)如何处理请求-小白菜博客
这里继续向下调用filterChain.doFilter方法

ApplicationFilterChain#doFilter

这个方法的参数已经被处理成了ServletRequest和ServletResponse了。 这里会进一步调用internalDoFilter方法。

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) {
			Exception e = pe.getException();
			if (e instanceof ServletException) {
				throw (ServletException) e;
			} else if (e instanceof IOException) {
				throw (IOException) e;
			} else if (e instanceof RuntimeException) {
				throw (RuntimeException) e;
			} else {
				throw new ServletException(e.getMessage(), e);
			}
		}
	} else {
		internalDoFilter(request,response);
	}
}

ApplicationFilterChain#internalDoFilter

分析到这个方法里面,分析整个tomcat处理请求的过程才算有了答案, 这里最核心的逻辑会调用HttpServlet#service方法,而我们自己写的Servlet会继承HttpServlet, 然后去重写doGet或者doPost请求。

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;
	}

	try {
		if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
			lastServicedRequest.set(request);
			lastServicedResponse.set(response);
		}

		if (request.isAsyncSupported() && !servletSupportsAsync) {
			request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
		}
		
		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 {
		    //看到这句代码,就是我们整个处理请求中最核心的方法,也是大家最熟悉的方法, 这里也就是调用HttpServlet#service方法
			servlet.service(request, response);
		}
	} catch (IOException | ServletException | RuntimeException e) {
		throw e;
	} catch (Throwable e) {
		e = ExceptionUtils.unwrapInvocationTargetException(e);
		ExceptionUtils.handleThrowable(e);
		throw new ServletException(sm.getString("filterChain.servlet"), e);
	} finally {
		if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
			lastServicedRequest.set(null);
			lastServicedResponse.set(null);
		}
	}
}

tomcat处理请求-结束

通过上面的分析,最后会调用HttpServlet的service方法, 这个方法里大家就很熟悉了,声明了很多Hook方法,doGet,doPost,doPut根据自己的业务去扩展servet,实现Hook方法。

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String method = req.getMethod();

	if (method.equals(METHOD_GET)) {
		long lastModified = getLastModified(req);
		if (lastModified == -1) {
			doGet(req, resp);
		} else {
			long ifModifiedSince;
			try {
				ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
			} catch (IllegalArgumentException iae) {
				ifModifiedSince = -1;
			}
			if (ifModifiedSince < (lastModified / 1000 * 1000)) {
				maybeSetLastModified(resp, lastModified);
				doGet(req, resp);
			} else {
				resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			}
		}

	} else if (method.equals(METHOD_HEAD)) {
		long lastModified = getLastModified(req);
		maybeSetLastModified(resp, lastModified);
		doHead(req, resp);
	} else if (method.equals(METHOD_POST)) {
		doPost(req, resp);
	} else if (method.equals(METHOD_PUT)) {
		doPut(req, resp);
	} else if (method.equals(METHOD_DELETE)) {
		doDelete(req, resp);
	} else if (method.equals(METHOD_OPTIONS)) {
		doOptions(req,resp);
	} else if (method.equals(METHOD_TRACE)) {
		doTrace(req,resp);
	} else {
		String errMsg = lStrings.getString("http.method_not_implemented");
		Object[] errArgs = new Object[1];
		errArgs[0] = method;
		errMsg = MessageFormat.format(errMsg, errArgs);

		resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
	}
}

总结

处理请求调用链路径

篇幅太长,我从Poller开始整理了处理请求的后续流程,整理成类调用链路径,来回顾下这一个完整的请求路径
tomcat-处理请求调用链.jpg

tomcat容器组件说明

在分析tomcat处理请求过程中,涉及到很多概念,tomcat是组件化开发,加上容器是嵌套的, 下面的图从整体上对容器内部有一个了解, 先了解整体,再去分析过程,就不会陷入这些源码调用链中。
1203643-20190109140742849-1831872540.png

  • Processor 组件负责读取消息报文,解析请求行,请求体,封装成Request。
  • Mapper 组件根据请求行的URL和请求头的Host值匹配由那个Host容器,Context容器,Wrapper容器去处理请求。
  • Adapter 组件负责把Connector和Engine关联起来, 把生成Request和Response对象传递到Engine容器中去。
  • Engine 容器组件,是Container全局负责处理Request和Response请求的入口,全局只有一个Engine实例, 其余Host,Context,Wrapper都是子容器。

参考资料

https://developer.aliyun.com/article/838576