ToB企服应用市场:ToB评测及商务社交产业平台

标题: servlet & tomcat [打印本页]

作者: 九天猎人    时间: 前天 13:49
标题: servlet & tomcat
在spring-mvc demo步调运行到DispatcherServlet的mvc处理 一文中,我们实践了欣赏器输入一个请求,然后到SpringMvc的DispatcherServlet处理的整个流程. 设计上这些都是tomcat servlet的处理

那么究竟这是怎么到DispatcherServlet处理的,本文将给出。

  
Tomcat架构

显然需要先了解tomcat, 可以下载tomcat源码分析。 其处理流程基本如下:

Tomcat包罗几个容器:Engine, Host, Context,Wrapper,Servlet,末了是Servlet实例实行service方法处理请求。
而Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵照的过程:
service()方法是实行现实使命的主要方法。Servlet 容器(即 Web 服务器)调用 service() 方法来处理来自客户端(欣赏器)的请求,并把格式化的响应写回给客户端。每次服务器接收到一个 Servlet 请求时,服务器会产生一个新的线程并调用服务。service() 方法检查 HTTP 请求范例(GET、POST、PUT、DELETE 等),并在适当的时候调用 doGet、doPost、doPut,doDelete等方法。
Connector

connector是什么?
The HTTP Connector element represents a Connector component that supports the HTTP/1.1 protocol. It enables Catalina to function as a stand-alone web server, in addition to its ability to execute servlets and JSP pages. A particular instance of this component listens for connections on a specific TCP port number on the server.One or more such Connectors can be configured as part of a single Service, each forwarding to the associated Engine to perform request processing and create the response.
(https://tomcat.apache.org/tomcat-8.0-doc/config/http.html)
HTTP Connector 能支持 HTTP/1.1 协议。它使 Catalina 可以或许作为独立的 Web 服务器运行,别的还可以或许实行 servlet 和 JSP 页面。此组件的特定实例会侦听服务器上特定 TCP 端口号上的连接。可以将一个或多个如许的 Connector 设置为单个服务的一部分,每个 Connector 都会转发到关联的 Engine 以实行请求处理并创建响应。
  1. public Connector(String protocol) {
  2.         setProtocol(protocol);
  3.         // Instantiate protocol handler
  4.         ProtocolHandler p = null;
  5.         try {
  6.             Class<?> clazz = Class.forName(protocolHandlerClassName);
  7.             p = (ProtocolHandler) clazz.getConstructor().newInstance();
  8.         } catch (Exception e) {
  9.             log.error(sm.getString(
  10.                     "coyoteConnector.protocolHandlerInstantiationFailed"), e);
  11.         } finally {
  12.             this.protocolHandler = p;
  13.         }
  14.         if (Globals.STRICT_SERVLET_COMPLIANCE) {
  15.             uriCharset = StandardCharsets.ISO_8859_1;
  16.         } else {
  17.             uriCharset = StandardCharsets.UTF_8;
  18.         }
  19.         // Default for Connector depends on this (deprecated) system property
  20.         if (Boolean.parseBoolean(System.getProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "false"))) {
  21.             encodedSolidusHandling = EncodedSolidusHandling.DECODE;
  22.         }
  23.     }
复制代码
第一句 setProtocol就根据设置了socket编程协议范例
  1. /**
  2.      * Set the Coyote protocol which will be used by the connector.
  3.      *
  4.      * @param protocol The Coyote protocol name
  5.      *
  6.      * @deprecated Will be removed in Tomcat 9. Protocol must be configured via
  7.      *             the constructor
  8.      */
  9.     @Deprecated
  10.     public void setProtocol(String protocol) {
  11.         boolean aprConnector = AprLifecycleListener.isAprAvailable() &&
  12.                 AprLifecycleListener.getUseAprConnector();
  13.         if ("HTTP/1.1".equals(protocol) || protocol == null) {
  14.             if (aprConnector) {
  15.                 setProtocolHandlerClassName("org.apache.coyote.http11.Http11AprProtocol");
  16.             } else {
  17.                 setProtocolHandlerClassName("org.apache.coyote.http11.Http11NioProtocol");
  18.             }
  19.         } else if ("AJP/1.3".equals(protocol)) {
  20.             if (aprConnector) {
  21.                 setProtocolHandlerClassName("org.apache.coyote.ajp.AjpAprProtocol");
  22.             } else {
  23.                 setProtocolHandlerClassName("org.apache.coyote.ajp.AjpNioProtocol");
  24.             }
  25.         } else {
  26.             setProtocolHandlerClassName(protocol);
  27.         }
  28.     }
复制代码
Http11NioProtocol -> NioEndpoint

接收tcp/ip请求的线程,Acceptor

  1. protected final void startAcceptorThreads() {
  2.   int count = getAcceptorThreadCount();
  3.     acceptors = new Acceptor[count];
  4.     for (int i = 0; i < count; i++) {
  5.         acceptors[i] = createAcceptor();
  6.         String threadName = getName() + "-Acceptor-" + i;
  7.         acceptors[i].setThreadName(threadName);
  8.         Thread t = new Thread(acceptors[i], threadName);
  9.         t.setPriority(getAcceptorThreadPriority());
  10.         t.setDaemon(getDaemon());
  11.         t.start();
  12.     }
  13. }
复制代码
直接:java.nio.channels.ServerSocketChannel#accept (所以时候都要知道socket编程和tcp协议,IO底子可复习:https://doctording.blog.csdn.net/article/details/145839941)
  1. /**
  2. * The background thread that listens for incoming TCP/IP connections and
  3. * hands them off to an appropriate processor.
  4. */
  5. protected class Acceptor extends AbstractEndpoint.Acceptor {
  6. @Override
  7. public void run() {
  8.     int errorDelay = 0;
  9.     // Loop until we receive a shutdown command
  10.     while (running) {
  11.         // Loop if endpoint is paused
  12.         while (paused && running) {
  13.             state = AcceptorState.PAUSED;
  14.             try {
  15.                 Thread.sleep(50);
  16.             } catch (InterruptedException e) {
  17.                 // Ignore
  18.             }
  19.         }
  20.         if (!running) {
  21.             break;
  22.         }
  23.         state = AcceptorState.RUNNING;
  24.         try {
  25.             //if we have reached max connections, wait
  26.             countUpOrAwaitConnection();
  27.             SocketChannel socket = null;
  28.             try {
  29.                 // Accept the next incoming connection from the server
  30.                 // socket
  31.                 socket = serverSock.accept();
  32.             } catch (IOException ioe) {
  33.                 // We didn't get a socket
  34.                 countDownConnection();
  35.                 if (running) {
  36.                     // Introduce delay if necessary
  37.                     errorDelay = handleExceptionWithDelay(errorDelay);
  38.                     // re-throw
  39.                     throw ioe;
  40.                 } else {
  41.                     break;
  42.                 }
  43.             }
  44.             // Successful accept, reset the error delay
  45.             errorDelay = 0;
  46.             // Configure the socket
  47.             if (running && !paused) {
  48.                 // setSocketOptions() will hand the socket off to
  49.                 // an appropriate processor if successful
  50.                 if (!setSocketOptions(socket)) {
  51.                     closeSocket(socket);
  52.                 }
  53.             } else {
  54.                 closeSocket(socket);
  55.             }
  56.         } catch (Throwable t) {
  57.             ExceptionUtils.handleThrowable(t);
  58.             log.error(sm.getString("endpoint.accept.fail"), t);
  59.         }
  60.     }
  61.     state = AcceptorState.ENDED;
  62. }
复制代码
处理socket连接数据的线程,Poller

Acceptor的到的连接socket,举行如下处理
  1. /**
  2. * Process the specified connection.
  3. * @param socket The socket channel
  4. * @return <code>true</code> if the socket was correctly configured
  5. *  and processing may continue, <code>false</code> if the socket needs to be
  6. *  close immediately
  7. */
  8. protected boolean setSocketOptions(SocketChannel socket) {
  9.    // Process the connection
  10.    try {
  11.        //disable blocking, APR style, we are gonna be polling it
  12.        socket.configureBlocking(false);
  13.        Socket sock = socket.socket();
  14.        socketProperties.setProperties(sock);
  15.        NioChannel channel = nioChannels.pop();
  16.        if (channel == null) {
  17.            SocketBufferHandler bufhandler = new SocketBufferHandler(
  18.                    socketProperties.getAppReadBufSize(),
  19.                    socketProperties.getAppWriteBufSize(),
  20.                    socketProperties.getDirectBuffer());
  21.            if (isSSLEnabled()) {
  22.                channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
  23.            } else {
  24.                channel = new NioChannel(socket, bufhandler);
  25.            }
  26.        } else {
  27.            channel.setIOChannel(socket);
  28.            channel.reset();
  29.        }
  30.        getPoller0().register(channel);
  31.    } catch (Throwable t) {
  32.        ExceptionUtils.handleThrowable(t);
  33.        try {
  34.            log.error("",t);
  35.        } catch (Throwable tt) {
  36.            ExceptionUtils.handleThrowable(tt);
  37.        }
  38.        // Tell to close the socket
  39.        return false;
  40.    }
  41.    return true;
  42. }
复制代码
Pollor类定义如下:
Pollor负责轮询网络连接上的数据。在 NIO 或 NIO2 模型中,Poller 线程会检查注册在其上的 Channel(例如,SocketChannel)是否有数据可读或可写。
此中使用了java nio的Selector,即允许一个单一的线程来操作多个 Channel.
  1. /**
  2. * Poller class.
  3. */
  4. public class Poller implements Runnable {
  5.     private Selector selector;
  6.     private final SynchronizedQueue<PollerEvent> events =
  7.             new SynchronizedQueue<>();
  8.     private volatile boolean close = false;
  9.     private long nextExpiration = 0;//optimize expiration handling
  10.     private AtomicLong wakeupCounter = new AtomicLong(0);
  11.     private volatile int keyCount = 0;
  12.     public Poller() throws IOException {
  13.         this.selector = Selector.open();
  14.     }
复制代码
socket详细的读写处理,Processor(Executor线程池)

Poller判断连接是否有读写,交给Processor详细处理
  1. protected void processKey(SelectionKey sk, NioSocketWrapper attachment) {
  2.     try {
  3.         if ( close ) {
  4.             cancelledKey(sk);
  5.         } else if ( sk.isValid() && attachment != null ) {
  6.             if (sk.isReadable() || sk.isWritable() ) {
  7.                 if ( attachment.getSendfileData() != null ) {
  8.                     processSendfile(sk,attachment, false);
  9.                 } else {
  10.                     unreg(sk, attachment, sk.readyOps());
  11.                     boolean closeSocket = false;
  12.                     // Read goes before write
  13.                     if (sk.isReadable()) {
  14.                         if (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
  15.                             closeSocket = true;
  16.                         }
  17.                     }
  18.                     if (!closeSocket && sk.isWritable()) {
  19.                         if (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
  20.                             closeSocket = true;
  21.                         }
  22.                     }
  23.                     if (closeSocket) {
  24.                         cancelledKey(sk);
  25.                     }
  26.                 }
  27.             }
  28.         } else {
  29.             //invalid key
  30.             cancelledKey(sk);
  31.         }
  32.     } catch ( CancelledKeyException ckx ) {
  33.         cancelledKey(sk);
  34.     } catch (Throwable t) {
  35.         ExceptionUtils.handleThrowable(t);
  36.         log.error("",t);
  37.     }
  38. }
复制代码
背后是扩展的Executor线程池处理
  1. /**
  2.      * This class is the equivalent of the Worker, but will simply use in an
  3.      * external Executor thread pool.
  4.      */
  5.     protected class SocketProcessor extends SocketProcessorBase<NioChannel> {
  6.         public SocketProcessor(SocketWrapperBase<NioChannel> socketWrapper, SocketEvent event) {
  7.             super(socketWrapper, event);
  8.         }
  9.         @Override
  10.         protected void doRun() {
  11.             NioChannel socket = socketWrapper.getSocket();
  12.             SelectionKey key = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
  13.             try {
  14.                 int handshake = -1;
  15.                 try {
  16.                     if (key != null) {
  17.                         if (socket.isHandshakeComplete()) {
  18.                             // No TLS handshaking required. Let the handler
  19.                             // process this socket / event combination.
  20.                             handshake = 0;
  21.                         } else if (event == SocketEvent.STOP || event == SocketEvent.DISCONNECT ||
  22.                                 event == SocketEvent.ERROR) {
  23.                             // Unable to complete the TLS handshake. Treat it as
  24.                             // if the handshake failed.
  25.                             handshake = -1;
  26.                         } else {
  27.                             handshake = socket.handshake(key.isReadable(), key.isWritable());
  28.                             // The handshake process reads/writes from/to the
  29.                             // socket. status may therefore be OPEN_WRITE once
  30.                             // the handshake completes. However, the handshake
  31.                             // happens when the socket is opened so the status
  32.                             // must always be OPEN_READ after it completes. It
  33.                             // is OK to always set this as it is only used if
  34.                             // the handshake completes.
  35.                             event = SocketEvent.OPEN_READ;
  36.                         }
  37.                     }
  38.                 } catch (IOException x) {
  39.                     handshake = -1;
  40.                     if (log.isDebugEnabled()) log.debug("Error during SSL handshake",x);
  41.                 } catch (CancelledKeyException ckx) {
  42.                     handshake = -1;
  43.                 }
  44.                 if (handshake == 0) {
  45.                     SocketState state = SocketState.OPEN;
  46.                     // Process the request from this socket
  47.                     if (event == null) {
  48.                         state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ);
  49.                     } else {
  50.                         state = getHandler().process(socketWrapper, event);
  51.                     }
  52.                     if (state == SocketState.CLOSED) {
  53.                         close(socket, key);
  54.                     }
  55.                 } else if (handshake == -1 ) {
  56.                     getHandler().process(socketWrapper, SocketEvent.CONNECT_FAIL);
  57.                     close(socket, key);
  58.                 } else if (handshake == SelectionKey.OP_READ){
  59.                     socketWrapper.registerReadInterest();
  60.                 } else if (handshake == SelectionKey.OP_WRITE){
  61.                     socketWrapper.registerWriteInterest();
  62.                 }
  63.             } catch (CancelledKeyException cx) {
  64.                 socket.getPoller().cancelledKey(key);
  65.             } catch (VirtualMachineError vme) {
  66.                 ExceptionUtils.handleThrowable(vme);
  67.             } catch (Throwable t) {
  68.                 log.error("", t);
  69.                 socket.getPoller().cancelledKey(key);
  70.             } finally {
  71.                 socketWrapper = null;
  72.                 event = null;
  73.                 //return to cache
  74.                 if (running && !paused) {
  75.                     processorCache.push(this);
  76.                 }
  77.             }
  78.         }
  79.     }
复制代码
详细在抽象类AbstractEndpoint中org.apache.tomcat.util.net.AbstractEndpoint#processSocket

  1. /**
  2. * Process the given SocketWrapper with the given status. Used to trigger
  3. * processing as if the Poller (for those endpoints that have one)
  4. * selected the socket.
  5. *
  6. * @param socketWrapper The socket wrapper to process
  7. * @param event         The socket event to be processed
  8. * @param dispatch      Should the processing be performed on a new
  9. *                          container thread
  10. *
  11. * @return if processing was triggered successfully
  12. */
  13. public boolean processSocket(SocketWrapperBase<S> socketWrapper,
  14.         SocketEvent event, boolean dispatch) {
  15.     try {
  16.         if (socketWrapper == null) {
  17.             return false;
  18.         }
  19.         SocketProcessorBase<S> sc = processorCache.pop();
  20.         if (sc == null) {
  21.             sc = createSocketProcessor(socketWrapper, event);
  22.         } else {
  23.             sc.reset(socketWrapper, event);
  24.         }
  25.         Executor executor = getExecutor();
  26.         if (dispatch && executor != null) {
  27.             executor.execute(sc);
  28.         } else {
  29.             sc.run();
  30.         }
  31.     } catch (RejectedExecutionException ree) {
  32.         getLog().warn(sm.getString("endpoint.executor.fail", socketWrapper) , ree);
  33.         return false;
  34.     } catch (Throwable t) {
  35.         ExceptionUtils.handleThrowable(t);
  36.         // This means we got an OOM or similar creating a thread, or that
  37.         // the pool and its queue are full
  38.         getLog().error(sm.getString("endpoint.process.fail"), t);
  39.         return false;
  40.     }
  41.     return true;
  42. }
复制代码
(大概差异版本不一样,如上是在tomcat-8.5.57源码中)
org.apache.coyote.http11.Http11Processor#service

详细的processor处理,则依据设置和socket连接,如Http11Processor处理如下:
  1. @Override
  2.     public SocketState service(SocketWrapperBase<?> socketWrapper)
  3.         throws IOException {
  4.         RequestInfo rp = request.getRequestProcessor();
  5.         rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
  6.         // Setting up the I/O
  7.         setSocketWrapper(socketWrapper);
  8.         // Flags
  9.         keepAlive = true;
  10.         openSocket = false;
  11.         readComplete = true;
  12.         boolean keptAlive = false;
  13.         SendfileState sendfileState = SendfileState.DONE;
  14.         while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
  15.                 sendfileState == SendfileState.DONE && !endpoint.isPaused()) {
  16.             // Parsing the request header
  17.             try {
  18.                 if (!inputBuffer.parseRequestLine(keptAlive)) {
  19.                     if (inputBuffer.getParsingRequestLinePhase() == -1) {
  20.                         return SocketState.UPGRADING;
  21.                     } else if (handleIncompleteRequestLineRead()) {
  22.                         break;
  23.                     }
  24.                 }
  25.                 // Process the Protocol component of the request line
  26.                 // Need to know if this is an HTTP 0.9 request before trying to
  27.                 // parse headers.
  28.                 prepareRequestProtocol();
  29.                 if (endpoint.isPaused()) {
  30.                     // 503 - Service unavailable
  31.                     response.setStatus(503);
  32.                     setErrorState(ErrorState.CLOSE_CLEAN, null);
  33.                 } else {
  34.                     keptAlive = true;
  35.                     // Set this every time in case limit has been changed via JMX
  36.                     request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
  37.                     // Don't parse headers for HTTP/0.9
  38.                     if (!http09 && !inputBuffer.parseHeaders()) {
  39.                         // We've read part of the request, don't recycle it
  40.                         // instead associate it with the socket
  41.                         openSocket = true;
  42.                         readComplete = false;
  43.                         break;
  44.                     }
  45.                     if (!disableUploadTimeout) {
  46.                         socketWrapper.setReadTimeout(connectionUploadTimeout);
  47.                     }
  48.                 }
复制代码
关键处理在getAdapter().service(request, response);

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4