概述

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



找到了这一步,才算看到了核心内容,声明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接口,所以这两个类都是线程相关, 这两个类在接收请求和处理请求的过程中起了承上启下的作用。 这里我们通过三张图来看看他们是怎么工作的。

截图一

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

截图二

截图三

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



这里继续向下调用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容器组件说明

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

  • 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

tomcat源码分析(二)如何处理请求的更多相关文章

  1. Tomcat源码分析二:先看看Tomcat的整体架构

    Tomcat源码分析二:先看看Tomcat的整体架构 Tomcat架构图 我们先来看一张比较经典的Tomcat架构图: 从这张图中,我们可以看出Tomcat中含有Server.Service.Conn ...

  2. Tomcat 源码分析(转)

    本文转自:http://blog.csdn.net/haitao111313/article/category/1179996 Tomcat源码分析(一)--服务启动 1. Tomcat主要有两个组件 ...

  3. Tomcat源码分析三:Tomcat启动加载过程(一)的源码解析

    Tomcat启动加载过程(一)的源码解析 今天,我将分享用源码的方式讲解Tomcat启动的加载过程,关于Tomcat的架构请参阅<Tomcat源码分析二:先看看Tomcat的整体架构>一文 ...

  4. Tomcat源码分析(二)------ 一次完整请求的里里外外

    Tomcat源码分析(二)------ 一次完整请求的里里外外   前几天分析了一下Tomcat的架构和启动过程,今天开始研究它的运转机制.Tomcat最本质就是个能运行JSP/Servlet的Web ...

  5. Tomcat源码分析——请求原理分析(上)

    前言 谈起Tomcat的诞生,最早可以追溯到1995年.近20年来,Tomcat始终是使用最广泛的Web服务器,由于其使用Java语言开发,所以广为Java程序员所熟悉.很多人早期的J2EE项目,由程 ...

  6. tomcat源码分析(三)一次http请求的旅行-从Socket说起

    p { margin-bottom: 0.25cm; line-height: 120% } tomcat源码分析(三)一次http请求的旅行 在http请求旅行之前,我们先来准备下我们所需要的工具. ...

  7. [Tomcat 源码分析系列] (二) : Tomcat 启动脚本-catalina.bat

    概述 Tomcat 的三个最重要的启动脚本: startup.bat catalina.bat setclasspath.bat 上一篇咱们分析了 startup.bat 脚本 这一篇咱们来分析 ca ...

  8. Tomcat源码分析——请求原理分析(下)

    前言 本文继续讲解TOMCAT的请求原理分析,建议朋友们阅读本文时首先阅读过<TOMCAT源码分析——请求原理分析(上)>和<TOMCAT源码分析——请求原理分析(中)>.在& ...

  9. Tomcat源码分析——请求原理分析(中)

    前言 在<TOMCAT源码分析——请求原理分析(上)>一文中已经介绍了关于Tomcat7.0处理请求前作的初始化和准备工作,请读者在阅读本文前确保掌握<TOMCAT源码分析——请求原 ...

  10. Tomcat源码分析

    前言: 本文是我阅读了TOMCAT源码后的一些心得. 主要是讲解TOMCAT的系统框架, 以及启动流程.若有错漏之处,敬请批评指教! 建议: 毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, ...

随机推荐

  1. 异常处理、逻辑与(&)在条件结束判定的应用

    例子:求1+2+-+n的和,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C)(注 题目来自力扣) (1)boolean和逻辑与(&am ...

  2. LiveData

    ViewModel 添加依赖 implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' activity_main.xml < ...

  3. 「模拟赛」多校 A 层联训 16

    比赛链接 A.四舍五入 虽然让找 \(i\),但枚举 \(i\) 很没前途啊,所以考虑找到所有 \(j\) 的个数 发现对于一组合法的 \(i.j\) 需要满足 \(i\in [kj,\ kj+0.5 ...

  4. 剖析Air724UG的硬件设计,有大发现?03篇

    ​ 今天我们分享第三部分. 四.射频接口 天线接口管脚定义如下: 表格 19:RF_ANT 管脚定义 管脚名 序号 描述 LTE_ANT 46 LTE 天线接口 BT/WiFi_ANT 34 蓝牙/W ...

  5. CF2023C C+K+S 题解

    题面 给您两个强联通的 \(^{\dagger}\) 有向图,每个图都有精确的 \(n\) 个顶点,但可能有不同数量的边.仔细观察后,您发现了一个重要特征--这些图中任何一个环的长度都能被 \(k\) ...

  6. 设计一个基于 LSTM 神经网络的文本分类器

    前一篇:<用于自然语言处理的循环神经网络RNN> 序言:本节主要讲解如何使用循环神经网络(RNN)创建一个文本分类器.RNN 是一类适合处理序列数据的神经网络的统称,而我们将在本节中使用 ...

  7. Apache+JK+Tomcat 负载平衡配置

    网 上关于 Apache + JK + Tomcat 的集群配置例子很多,按着例子配置下来,基本都能运行,不过,在一些重要的地方却没有进一步的说明.这次公司一个产品就是采用Apache+JK+Tomc ...

  8. An expression evaluator

    An expression evaluator  Download source code (17 kb) Two weeks ago, I saw an article on codeproject ...

  9. ant 组件全局设置中文 vue

    //引入中文组件import zhCN from 'ant-design-vue/es/locale/zh_CN';//定义 const  locale = zhCN   //包裹根组件 <a- ...

  10. 一个.NET开源、免费、功能强大的 PDF 处理工具

    前言 在日常工作中PDF文档的处理往往受限于其固有的格式,使得用户在编辑.合并.剪裁等方面面临诸多不便.今天大姚给大家分享一个.NET开源.免费.功能强大的 PDF 处理工具:PDF 补丁丁(PDFP ...