在Tomcat的启动流程一文中分析到在AbstractEndpoint中会创建服务端socket并绑定地址进行监听,但没有涉及当请求进来之后Tomcat是怎么处理的。本文就来分析一下该问题。
本文以默认使用的Http11NioProtocol这个协议处理器为例,其他协议处理器也可以参考,大体思路是相似的。
网络事件模型
在NioEndpoint组件的启动过程中,会创建并启动Acceptor线程和Poller线程,这两个类都是NioEndpoint中的内部类,下面分别看看它们的run方法做了什么事情。
Acceptor
@Override
public void run() {
int errorDelay = 0;
// Loop until we receive a shutdown command
// 事件循环
while (running) {
// Loop if endpoint is paused
// 如果需要暂停运行状态
while (paused && running) {
state = AcceptorState.PAUSED;
try {
// 暂停50毫秒
Thread.sleep(50);
} catch (InterruptedException e) {
// Ignore
}
}
// 结束运行则退出循环
if (!running) {
break;
}
state = AcceptorState.RUNNING;
try {
//if we have reached max connections, wait
// 下面准备接收新连接的,先让门闩加1;如果已经达到最大值,则阻塞等待。
countUpOrAwaitConnection();
SocketChannel socket = null;
try {
// Accept the next incoming connection from the server
// socket
/*
* 接收客户端的连接,在bind方法中,serverSock被设置为阻塞模式,所以这里会阻塞直到有客户端连接。
* 如果有多个Acceptor,怎么保证一个请求不被多个acceptor线程处理了?
*/
socket = serverSock.accept();
} catch (IOException ioe) {
// We didn't get a socket
// 没有获取到socket,则让门闩减1
countDownConnection();
if (running) {
// Introduce delay if necessary
// 处理异常
errorDelay = handleExceptionWithDelay(errorDelay);
// re-throw
throw ioe;
} else {
break;
}
}
// Successful accept, reset the error delay
errorDelay = 0;
// Configure the socket
if (running && !paused) {
// setSocketOptions() will hand the socket off to
// an appropriate processor if successful
/*
* 通过setSocketOptions处理客户端的连接请求。
*/
if (!setSocketOptions(socket)) {
closeSocket(socket);
}
} else {
closeSocket(socket);
}
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
log.error(sm.getString("endpoint.accept.fail"), t);
}
}
state = AcceptorState.ENDED;
}
通过调用底层JDK的ServerSocketChannel类的accept方法来获取连接,由于在NioEndpoint的bind方法中是设置的阻塞模式,所以这里如果没有请求到来则会阻塞在这里。接受到请求后,会调用setSocketOptions方法来处理请求。
protected boolean setSocketOptions(SocketChannel socket) {
// Process the connection
try {
//disable blocking, APR style, we are gonna be polling it
// 和serverSocket不同,客户端连接的socket设置为非阻塞模式。
socket.configureBlocking(false);
// 获取socket对象
Socket sock = socket.socket();
// 设置socket的一些属性
socketProperties.setProperties(sock);
/*
* nioChannels是一个队列,用于缓存客户端的连接通道对象,避免每次新进来连接就创建。
* 这里的NioChannel是Tomcat中对网络通道的封装。
*/
NioChannel channel = nioChannels.pop();
if (channel == null) { // 如果没获取到缓存的通道对象,则新建
SocketBufferHandler bufhandler = new SocketBufferHandler(
socketProperties.getAppReadBufSize(),
socketProperties.getAppWriteBufSize(),
socketProperties.getDirectBuffer());
// 新建通道对象, 并将channel和表示客户端连接的socket关联
if (isSSLEnabled()) {
channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
} else {
channel = new NioChannel(socket, bufhandler);
}
} else { // 如果有缓存的通道,那么将其和当前的socket关联
channel.setIOChannel(socket);
// 重置一些属性
channel.reset();
}
// 将channel封装为PollEvent,并加入到队列中,poller线程会处理。
getPoller0().register(channel);
}
return true;
}
public void setProperties(Socket socket) throws SocketException{
if (rxBufSize != null) // 设置接收缓冲区大小
socket.setReceiveBufferSize(rxBufSize.intValue());
if (txBufSize != null) // 设置发送缓冲区大小
socket.setSendBufferSize(txBufSize.intValue());
if (ooBInline !=null) // 选项开启时,带外数据将被留在正常的输入队列中
socket.setOOBInline(ooBInline.booleanValue());
if (soKeepAlive != null) // TCP保活机制
socket.setKeepAlive(soKeepAlive.booleanValue());
if (performanceConnectionTime != null && performanceLatency != null &&
performanceBandwidth != null)
// 设置性能选项
socket.setPerformancePreferences(
performanceConnectionTime.intValue(),
performanceLatency.intValue(),
performanceBandwidth.intValue());
if (soReuseAddress != null) // 设置地址重用
socket.setReuseAddress(soReuseAddress.booleanValue());
if (soLingerOn != null && soLingerTime != null)
// 设置在关闭socket时是否等数据发送完,第二个参数是最多等待的时间
socket.setSoLinger(soLingerOn.booleanValue(),
soLingerTime.intValue());
if (soTimeout != null && soTimeout.intValue() >= 0)
// 设置接收数据的超时时间
socket.setSoTimeout(soTimeout.intValue());
if (tcpNoDelay != null) {
try {
// 是否禁用TCP的Nagle算法
socket.setTcpNoDelay(tcpNoDelay.booleanValue());
} catch (SocketException e) {
// Some socket types may not support this option which is set by default
}
}
}
最重要的是会选择一个poller线程,并将请求注册到它的队列中,供poller线程处理。先来看看选择poller的算法。
public Poller getPoller0() {
/*
* 这里采用的是轮询法,通过自增取余来实现,和Netty中的GenericEventExecutorChooser类似,当然这里是在选poller,而不是worker。
* 采用Math.abs是为了防止自增导致的溢出,确保下标是合法的。
*/
int idx = Math.abs(pollerRotater.incrementAndGet()) % pollers.length;
return pollers[idx];
}
这里是直接使用的轮询法,通过自增取余来实现。然后Acceptor线程会将请求注册到poller线程中。
private final SynchronizedQueue<PollerEvent> events =
new SynchronizedQueue<>();
private void addEvent(PollerEvent event) {
events.offer(event);
if ( wakeupCounter.incrementAndGet() == 0 ) selector.wakeup();
}
/*
* 虽然该方法���Poller类中,但是是被Acceptor调用的。
* 用于实现Acceptor和Poller两种线程的交互。
*/
public void register(final NioChannel socket) {
socket.setPoller(this);
// 创建wrapper对象,用于包装NioChannel和NioEndpoint对象。
NioSocketWrapper ka = new NioSocketWrapper(socket, NioEndpoint.this);
socket.setSocketWrapper(ka);
// 设置poller为this,后续在selector中注册的时候会获取
ka.setPoller(this);
// 设置socket的一些属性
ka.setReadTimeout(getSocketProperties().getSoTimeout());
ka.setWriteTimeout(getSocketProperties().getSoTimeout());
ka.setKeepAliveLeft(NioEndpoint.this.getMaxKeepAliveRequests());
ka.setReadTimeout(getConnectionTimeout());
ka.setWriteTimeout(getConnectionTimeout());
/*
* 和NioChannel类似,这里从对象池中获取PollerEvent。
* PollerEvent(简称PE)是Acceptor和Poller交互的媒介。
* Acceptor收到请求后会调用该方法封装为PollerEvent,然后添加到队列中。
* Poller线程从队列中获取PE,然后进行处理。
*/
PollerEvent r = eventCache.pop();
// 设置��兴趣的事件为读
ka.interestOps(SelectionKey.OP_READ);//this is what OP_REGISTER turns into.
// 如果没缓存,则创建pe对象,事件类型是REGISTER。后续在PollerEvent的run方法中会处理。
if ( r==null) r = new PollerEvent(socket,ka,OP_REGISTER);
// 如果有缓存,则重置数据,注意事件类型是REGISTER。
else r.reset(socket,ka,OP_REGISTER);
/*
* 将pe对象添加到队列中,poller线程会从队列中取出来处理。
* 至此,Acceptor线程完成任务,接下来就是Poller线程处理任务了。
*/
addEvent(r);
}
在该方法中主要做了下面几件事情:
- 将请求封装为NioSocketWrapper类型的对象ka;
- 将ka对象封装到PollerEvent对象r中;
- 将事件对象r添加到队列中;
注意,尽管该方法是Poller类中的方法,但是执行该方法的还是Acceptor线程,执行完该方法后,Acceptor的针对该请求的任务就结束了,又回到事件循环中准备接收下一个连接。
Poller线程
@Override
public void run() {
// Loop until destroy() is called
// 事件循环,不断处理队列中的事件
while (true) {
boolean hasEvents = false;
try {
if (!close) {
// 处理队列中的事件
hasEvents = events();
// 执行select操作,获取已就绪的IO事件。
if (wakeupCounter.getAndSet(-1) > 0) {
//if we are here, means we have other stuff to do
//do a non blocking select
keyCount = selector.selectNow();
} else {
keyCount = selector.select(selectorTimeout);
}
wakeupCounter.set(0);
}
if (close) {
// 结束运行之前先把队列中的任务执行完
events();
timeout(0, false);
try {
// 关闭selector
selector.close();
} catch (IOException ioe) {
log.error(sm.getString("endpoint.nio.selectorCloseFail"), ioe);
}
break;
}
} catch (Throwable x) {
ExceptionUtils.handleThrowable(x);
log.error("",x);
continue;
}
//either we timed out or we woke up, process events first
// hasEvents记录是否处理了事件
if ( keyCount == 0 ) hasEvents = (hasEvents | events());
// 如果有已就绪的事件,那么获取迭代器,准备迭代并处理。
Iterator<SelectionKey> iterator =
keyCount > 0 ? selector.selectedKeys().iterator() : null;
// Walk through the collection of ready keys and dispatch
// any active event.
// 遍历已就绪事件
while (iterator != null && iterator.hasNext()) {
SelectionKey sk = iterator.next();
NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment();
// Attachment may be null if another thread has called
// cancelledKey()
if (attachment == null) {
iterator.remove();
} else {
iterator.remove();
// 处理IO事件
processKey(sk, attachment);
}
}//while
//process timeouts
timeout(keyCount,hasEvents);
}//while
// 对stop门闩减1
getStopLatch().countDown();
}
通过该方法可以看出Poller线程中主要做两件事件:
- 处理队列中的任务;
- 处理selector中的就绪事件;
注册新连接
public boolean events() {
boolean result = false;
PollerEvent pe = null;
// 从队列中获取PE对象
for (int i = 0, size = events.size(); i < size && (pe = events.poll()) != null; i++ ) {
result = true;
try {
// 执行pe
pe.run();
// 重置pe对象
pe.reset();
if (running && !paused) {
// 将pe加入到对象池中
eventCache.push(pe);
}
} catch ( Throwable x ) {
log.error("",x);
}
}
return result;
}
该方法主要在调用PollerEvent事件对象,该类实现了Runnable接口,但是在该方法中,是直接调用的其run方法。
@Override
public void run() {
if (interestOps == OP_REGISTER) { // 如果是注册操作
try {
/*
* 将客户端的连接请求注册到selector中,感兴趣的事件是读,attachment是wrapper对象。
* tomcat中最多只有2个poller,这里是每个poller都有一个selector,获取的是当前Poller线程中的selector。
*/
socket.getIOChannel().register(
socket.getPoller().getSelector(), SelectionKey.OP_READ, socketWrapper);
} catch (Exception x) {
log.error(sm.getString("endpoint.nio.registerFail"), x);
}
} else { // 其他类型的操作
}
}
在该方法中,如果发现是需要注册的新连接,那么会将请求注册到selector中,这样后续在Poller线程的事件循环中就能处理了。
处理请求
protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
try {
// 如果poller线程被关闭,
if ( close ) {
// 则取消key
cancelledKey(sk);
} else if ( sk.isValid() && attachment != null ) {
// 判断就绪的事件是不是读写事件
if (sk.isReadable() || sk.isWritable() ) {
// 如果使用sendfile
if ( attachment.getSendfileData() != null ) {
// 处理sendfile
processSendfile(sk,attachment, false);
} else {
unreg(sk, attachment, sk.readyOps());
boolean closeSocket = false;
// Read goes before write
// 读事件
if (sk.isReadable()) {
// 处理客户端的请求
if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
closeSocket = true;
}
}
// 写事件
if (!closeSocket && sk.isWritable()) {
if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
closeSocket = true;
}
}
// 如果处理读写事件失败
if (closeSocket) {
cancelledKey(sk);
}
}
}
} else {
//invalid key
cancelledKey(sk);
}
}
}
在该方法中会调用processSocket来处理请求。
public boolean processSocket(SocketWrapperBase<S> socketWrapper,
SocketEvent event, boolean dispatch) {
try {
if (socketWrapper == null) {
return false;
}
// 同样地,从对象池中获取对象。
SocketProcessorBase<S> sc = processorCache.pop();
if (sc == null) {
// 如果没有缓存,则创建新对象。不同的子类,创建不同类型的SocketProcessorBase实现。
sc = createSocketProcessor(socketWrapper, event);
} else {
sc.reset(socketWrapper, event);
}
/*
* 获取线程池对象,虽然可能poller线程有多个, 每个poller线程又有自己单独的selector。
* 但是线程池对象是属于endpoint的,所以多个poller线程对应一个线程池。
*/
Executor executor = getExecutor();
if (dispatch && executor != null) {
// 提交到线程池中处理
executor.execute(sc);
} else {
// 如果没有线程池,则直接在poller线程中执行。
sc.run();
}
}
return true;
}
在该方法中,会把SocketWrapperBase对象封装到SocketProcessorBase对象中,然后把后者提交到线程池中执行。
至此Poller线程针对该请求的任务就结束了,后续的操作都是在线程池中进行的。
SocketProcessorBase
@Override
public final void run() {
synchronized (socketWrapper) {
// It is possible that processing may be triggered for read and
// write at the same time. The sync above makes sure that processing
// does not occur in parallel. The test below ensures that if the
// first event to be processed results in the socket being closed,
// the subsequent events are not processed.
if (socketWrapper.isClosed()) {
return;
}
doRun();
}
}
protected abstract void doRun();
doRun方法由子类实现,这里仍然参考NioEndpoing中的内部类SocketProcessor的实现。
@Override
protected void doRun() {
// 获取通道对象
NioChannel socket = socketWrapper.getSocket();
// 获取在poller线程的selector中的注册键
SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
try {
if (handshake == 0) { // 处理正常请求
SocketState state = SocketState.OPEN;
// Process the request from this socket
/*
* getHandler返回的是AbstractProtocol中的ConnectionHandler,调用其process进行处理。
* 执行当前方法的线程是AbstractEndPoint中executor线程池中的线程。
*/
if (event == null) {
// 获取handler并处理
state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
} else {
state = getHandler().process(socketWrapper, event);
}
if (state == SocketState.CLOSED) {
close(socket, key);
}
} else if (handshake == -1 ) {
getHandler().process(socketWrapper, SocketEvent.CONNECT_FAIL);
close(socket, key);
} else if (handshake == SelectionKey.OP_READ){
socketWrapper.registerReadInterest();
} else if (handshake == SelectionKey.OP_WRITE){
socketWrapper.registerWriteInterest();
}
}
finally {
socketWrapper = null;
event = null;
//return to cache
if (running && !paused) {
processorCache.push(this);
}
}
}
在该方法中,主要是通过调用getHanlder来获取handler对象,然后调用其process方法。
getHandler方法主要是返回handler属性,那这个属性又是什么时候设置的呢?在创建ProtocolHandler的时候,在AbstractHttp11Protocol的构造方法中会设置。
public AbstractHttp11Protocol(AbstractEndpoint<S> endpoint) {
super(endpoint);
// 设置连接超时时间,默认是60秒
setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
// 创建并设置连接处理器
ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
setHandler(cHandler);
// 给endpoint对象设置handler,在线程池中会调用到该对象。
getEndpoint().setHandler(cHandler);
}
可以看到,这里创建的是ConnectionHandler,下面来看看它的process方法。
ConnectionHandler
该类定义在AbstractProtocol(ProtocolHandler接口的子类)中,实现了AbstractEndpoint的内部接口Handler。
@Override
public SocketState process(SocketWrapperBase<S> wrapper, SocketEvent status) {
// 从对象池中获取
processor = recycledProcessors.pop();
// 如果没有从对象池中获取到对象,则新建一个。
processor = getProtocol().createProcessor();
// 调用处理器的process方法。
state = processor.process(wrapper, status);
}
@Override
protected Processor createProcessor() {
/*
* 新建协议处理器
*/
Http11Processor processor = new Http11Processor(this, getEndpoint());
/*
* 设置adapter,这里的adapter是在Connector的initInternal方法中创建的,
* 并调用protocolHandler的setAdapter()方法设置的。
* 默认是CoyoteAdapter对象。
*/
processor.setAdapter(getAdapter());
processor.setMaxKeepAliveRequests(getMaxKeepAliveRequests());
processor.setConnectionUploadTimeout(getConnectionUploadTimeout());
processor.setDisableUploadTimeout(getDisableUploadTimeout());
processor.setRestrictedUserAgents(getRestrictedUserAgents());
processor.setMaxSavePostSize(getMaxSavePostSize());
return processor;
}
ConnectionHandler的process方法非常长,我们只关注请求处理部分就行,最终是调用了一个processor的process方法,那这个processor是什么呢。如果缓存中没有processor则会创建,我们根据这个线索去找,在AbstractHttp11Protocol中的createProcessor中找到了答案,就是Http11Processor。
Http11Processor是Tomcat中的一个Processor组件,继承体系如下图所示。注意和Http11NioProtocol进行区分,后者是ProtocolHanlder,一个是processor,一个是handler,在handler中会创建并通过processor来处理请求。
Http11Processor
创建
@SuppressWarnings("deprecation")
public Http11Processor(AbstractHttp11Protocol<?> protocol, AbstractEndpoint<?> endpoint) {
super(endpoint);
this.protocol = protocol;
httpParser = new HttpParser(protocol.getRelaxedPathChars(),
protocol.getRelaxedQueryChars());
inputBuffer = new Http11InputBuffer(request, protocol.getMaxHttpHeaderSize(),
protocol.getRejectIllegalHeader(), httpParser);
request.setInputBuffer(inputBuffer);
outputBuffer = new Http11OutputBuffer(response, protocol.getMaxHttpHeaderSize(),
protocol.getSendReasonPhrase());
response.setOutputBuffer(outputBuffer);
// Create and add the identity filters.
inputBuffer.addFilter(new IdentityInputFilter(protocol.getMaxSwallowSize()));
outputBuffer.addFilter(new IdentityOutputFilter());
// Create and add the chunked filters.
inputBuffer.addFilter(new ChunkedInputFilter(protocol.getMaxTrailerSize(),
protocol.getAllowedTrailerHeadersInternal(), protocol.getMaxExtensionSize(),
protocol.getMaxSwallowSize()));
outputBuffer.addFilter(new ChunkedOutputFilter());
// Create and add the void filters.
inputBuffer.addFilter(new VoidInputFilter());
outputBuffer.addFilter(new VoidOutputFilter());
// Create and add buffered input filter
inputBuffer.addFilter(new BufferedInputFilter());
// Create and add the gzip filters.
//inputBuffer.addFilter(new GzipInputFilter());
outputBuffer.addFilter(new GzipOutputFilter());
pluggableFilterIndex = inputBuffer.getFilters().length;
}
public AbstractProcessor(AbstractEndpoint<?> endpoint) {
this(endpoint, new Request(), new Response());
}
ic AbstractProcessor(AbstractEndpoint<?> endpoint) {
this(endpoint, new Request(), new Response());
注意在AbstractProcessor的构造方法中,创建了Request和Response对象,注意这两个类都是org.apache.coyote包下的,别和HttpServletReqeust和HttpServletResponse搞混了。
process
process方法定义在父类AbstractProcessorLight中。
@Override
public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
throws IOException {
// 如果是读事件,则调用service方法处理。
state = service(socketWrapper);
return state;
}
protected abstract SocketState service(SocketWrapperBase<?> socketWrapper) throws IOException;
service方法是个模板方法,下面来看看子类Http11Processor中的实现。该类中的实现也是非常长,这里挑选关键步骤。
@Override
public SocketState service(SocketWrapperBase<?> socketWrapper)
throws IOException {
/*
* 获取适配器,并执行其service方法,参考CoyoteAdapter。
* 这里的adapter是在Connector的initInternal方法中创建的,然后设置到protocolHandler中。
* 在protocolHandler的createProcessor方法中为新建的Processor对象设置了adapter。
*/
getAdapter().service(request, response);
}
这里会调用适配器的service方法,这个适配器是在哪里设置的呢?其实在AbstractHttp11Protocol创建Http11Processor对象后,就立马设置了适配器对象。而AbstractHttp11Protocol中的适配器对象是在Connection组件中的初始化过程中,被创建和设置进来的。该适配器对象是CoyoteAdapter类型的。
CoyoteAdapter
@Override
public void service(org.apache.coyote.Request req, org.apache.coyote.Response res)
throws Exception {
Request request = (Request) req.getNote(ADAPTER_NOTES);
Response response = (Response) res.getNote(ADAPTER_NOTES);
/*
* 第一次请求时,这里为null。
* 然后新建对象之后,就会通过setNote方法保存起来。
*/
if (request == null) {
// Create objects
/*
* 这里的connector就是StandardService中的子组件Connector。
*
* 这里在通过connector组件来创建request和response对象,分别是HttpServletRequest和HttpServletResponse类型的。
* Tomcat中connector包下的Request和Response分别实现了HttpServletRequest接口和HttpServletResponse接口。
* 注意区分req和Request,尽管两者的类名都是Request,但req是coyote包下的,而request是connector包下的。res和response同理。
*
* 两组类有什么区别?tomcat为什么要定义两组同名的类?
*/
request = connector.createRequest();
request.setCoyoteRequest(req);
response = connector.createResponse();
response.setCoyoteResponse(res);
// Link objects
// 将request和response互相关联
request.setResponse(response);
response.setRequest(request);
// Set as notes
req.setNote(ADAPTER_NOTES, request);
res.setNote(ADAPTER_NOTES, response);
// Set query string encoding
req.getParameters().setQueryStringCharset(connector.getURICharset());
}
if (connector.getXpoweredBy()) {
response.addHeader("X-Powered-By", POWERED_BY);
}
boolean async = false;
boolean postParseSuccess = false;
req.getRequestProcessor().setWorkerThreadName(THREAD_NAME.get());
try {
// Parse and set Catalina and configuration specific
// request parameters
/*
* 映射host, context和wrapper组件
*/
postParseSuccess = postParseRequest(req, request, res, response);
if (postParseSuccess) {
// Calling the container
/*
* 调用pipeline完成请求处理。
* 这里的getService()方法返回的是StandardService组件。
* getContainer()方法返回的是Engine组件,是StandardEngine。
* getPipeline()方法返回的是StandardPipeline,是在ContainerBase类中自动创建的(定义属性的时候就直接new初始化了)。
* getFirst()方法返回的是Pipeline中的first属性,参考StandardEngine构造器设置的basic属性。如果first为null,则返回basic。
* invoke()方法是在standardEngineValve中。
*/
connector.getService().getContainer().getPipeline().getFirst().invoke(
request, response);
}
else {
request.finishRequest();
response.finishResponse();
}
} catch (IOException e) {
// Ignore
} finally {
}
}
这里最重要的是在调用Connector的容器子组件,即StandardEngine的流水线pipeline中的Valve。
StandardEngineValve
/*
* 该方法在CoyoteAdapter中的service方法中会被调用。
*/
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// Select the Host to be used for this Request
// 从connector/Request中获取host组件对象
Host host = request.getHost();
// 如果找不到host
if (host == null) {
// HTTP 0.9 or HTTP 1.0 request without a host when no default host
// is defined.
// Don't overwrite an existing error
if (!response.isError()) {
// 响应404
response.sendError(404);
}
return;
}
// 异步相关
if (request.isAsyncSupported()) {
request.setAsyncSupported(host.getPipeline().isAsyncSupported());
}
// Ask this Host to process this request
// 调用host的pipeline处理请求
host.getPipeline().getFirst().invoke(request, response);
}
这里主要就是在调用Host组件的pipeline中的Valve。
StandardHostValve
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
if (!response.isErrorReportRequired()) {
// 调用Context的pipeline处理请求。
context.getPipeline().getFirst().invoke(request, response);
}
}
StandardContextValve
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// 获取wrapper对象。
Wrapper wrapper = request.getWrapper();
// 调用Wrapper的pipeline处理请求。
wrapper.getPipeline().getFirst().invoke(request, response);
}
StandardWrapperValve
@Override
public final void invoke(Request request, Response response)
throws IOException, ServletException {
// 创建过滤器链
ApplicationFilterChain filterChain =
ApplicationFilterFactory.createFilterChain(request, wrapper, servlet);
/*
* 执行过滤器链,
* 过滤器执行完后调用servlet。
*/
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
在doFilter方法中,又会调用到internalDoFilter方法。
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// 获取filter对象
Filter filter = filterConfig.getFilter();
// 执行filter
filter.doFilter(request, response, this);
/*
* 调用servlet的service方法,进入servlet的领域。
*/
servlet.service(request, response);
}
在该方法中,先是执行了过滤器,执行完后就会调用Servlet的service方法。
至此,请求在Tomcat中的入站部分执行完毕。
总结
本文大致上分析了请求的入站流程,可以发现整个流程涉及的内容还是很多的,为了突出主线,没有介绍太多其他内容,这些旁支内容适合单独写文章来介绍。