tomcat源码分析(二)如何处理请求
概述
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都是子容器。
参考资料
作者:sword-successful
出处:https://www.cnblogs.com/sword-successful/p/17162835.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
博客地址: | http://www.cnblogs.com/sword-successful/ |
博客版权: | 本文以学习、研究和分享为主,欢迎转载,但必须在文章页面明显位置给出原文连接。 如果文中有不妥或者错误的地方还望高手的你指出,以免误人子弟。如果觉得本文对你有所帮助不如【推荐】一下!如果你有更好的建议,不如留言一起讨论,共同进步! 再次感谢您耐心的读完本篇文章。 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2017-02-28 SpringMVC 集成velocity