Tomcat-Quellcodeanalyse und -Verarbeitung

Tomcat-Quellcodeanalyse und -Verarbeitung

Vorwort

Das vollständigste UML-Klassendiagramm von Tomcat

Bildbeschreibung hier einfügen

Tomcat-Anforderungsverarbeitungsprozess:

Bildbeschreibung hier einfügen

Wenn das Connector-Objekt erstellt wird, wird der ProtocolHandler von Http11NioProtocol erstellt. In der startInteral-Methode von Connector wird AbstractProtocol gestartet. AbstractProtocol startet NioEndPoint, um auf die Anfrage des Clients zu hören. Nachdem EndPoint die Anfrage des Clients empfangen hat, übergibt es sie an Container, um die Anfrage zu verarbeiten. Alle Container, die eine Anfrage ausgehend von der Engine durchläuft, enthalten ein Verantwortungskettenmuster. Jedes Mal, wenn ein Container durchläuft, wird die Verantwortungskette dieses Containers aufgerufen, um die Anfrage zu verarbeiten.

Bildbeschreibung hier einfügen

1. Endpunkt

Bildbeschreibung hier einfügen

Die Standardimplementierung von EndPoint ist NioEndPoint. NioEndPoint hat vier interne Klassen: Poller, Acceptor, PollerEvent, SocketProcessor und NioSocketWrapper.

(1) Der Acceptor ist für die Überwachung der Benutzeranforderungen verantwortlich. Nach der Überwachung der Benutzeranforderungen ruft er getPoller0().register(channel); kapselt zunächst die aktuelle Anforderung in ein PollerEvent, new PollerEvent(socket, ka, OP_REGISTER); kapselt die aktuelle Anforderung in ein Registrierungsereignis und fügt es der PollerEvent-Warteschlange hinzu und registriert dann das PollerEvent im Selector-Objekt des Pollers .

(2) Der Poller-Thread durchläuft weiterhin die Ereignisse, die verarbeitet werden können (Nettys Selestor). Wenn er das Ereignis findet, das verarbeitet werden muss, ruft er processKey(sk, socketWrapper); auf und führt die Run-Methode des zu verarbeitenden PollerEvent aus, um die Anforderung zu verarbeiten.

(3) PollerEvent erbt von der Schnittstelle Runnable. Wenn in seiner Run-Methode das Ereignis von PollerEvent darin besteht, OP_REGISTER zu registrieren, wird der aktuelle Socket beim Poller-Selektor registriert.

 öffentliche Leere ausführen() {
            wenn (interestOps == OP_REGISTER) {
                versuchen {
                	//Kerncode endlich gefunden! ! ! ! !
                    // Wenn das Ereignis eine Registrierung ist, registrieren Sie den aktuellen NioSocketChannel beim Selector des Pollers.
                    socket.getIOChannel().register(
                            socket.getPoller().getSelector(), SelectionKey.OP_READ, socketWrapper);
                } Fang (Ausnahme x) {
                    log.error(sm.getString("endpoint.nio.registerFail"), x);
                }
            } anders {
                endgültiger SelectionKey-Schlüssel = socket.getIOChannel().keyFor(socket.getPoller().getSelector());
                versuchen {
                    wenn (Schlüssel == null) {

                        // Der Schlüssel wurde gelöscht (zB durch Socket-Schließung)
                        // und aus dem Selektor entfernt, während dieser
                        // verarbeitet. Zählen Sie an dieser Stelle die Verbindungen herunter
                        // da der Countdown nicht abgelaufen ist, wenn der Socket
                        // geschlossen.
                        // Wenn SelectionKey abgebrochen wird, muss der Verbindungszähler des EndPoint, der dem SelectionKey entspricht, um eins reduziert werden socket.socketWrapper.getEndpoint().countDownConnection();
                        ((NioSocketWrapper) socket.socketWrapper).geschlossen = true;
                    } anders {
                        endgültiger NioSocketWrapper socketWrapper = (NioSocketWrapper) key.attachment();
                        wenn (socketWrapper != null) {
                            //Wir registrieren zunächst den Schlüssel und setzen den Fairnesszähler zurück.
                            int ops = key.interestOps() | InteresseOps;
                            socketWrapper.interestOps(ops);
                            Schlüssel.InteresseOps(ops);
                        } anders {
                            socket.getPoller().cancelledKey(Schlüssel);
                        }
                    }
                } Fang (CancelledKeyException ckx) {
                    versuchen {
                        socket.getPoller().cancelledKey(Schlüssel);
                    } catch (Ausnahme ignorieren) {
                    }
                }
            }
        }

(4) Der Poller-Thread führt keyCount = selector.select(selectorTimeout); aus, um die Anzahl der SelectionKeys zu ermitteln, die aktuell verarbeitet werden müssen. Wenn keyCount dann größer als 0 ist, ruft er den Iterator des Selectors ab, durchläuft alle erforderlichen SelectionKeys und verarbeitet sie. Hier wird das Socket-Ereignis in NioSocketWrapper gekapselt.

// Holen Sie sich den Iterator der ausgewählten Schlüssel Iterator<SelectionKey> iterator =
         Schlüsselanzahl > 0? selector.selectedKeys().iterator() : null;

 // Alle SelectionKeys durchlaufen und verarbeiten, während (Iterator != null und iterator.hasNext()) {
     Auswahlschlüssel sk = iterator.next();
     iterator.entfernen();
     NioSocketWrapper socketWrapper = (NioSocketWrapper) sk.attachment();
     // Anhang kann null sein, wenn ein anderer Thread aufgerufen hat
     // abgebrochenerSchlüssel()
     // Wenn ein Anhang vorhanden ist, verarbeite ihn if (socketWrapper != null) {
         //Ereignisse verarbeiten processKey(sk, socketWrapper);
     }
 }

processKey verarbeitet SelectionKey. Wenn der aktuelle Poller geschlossen wird, wird der Schlüssel gelöscht. Wenn im Kanal, der SelectionKey entspricht, ein Leseereignis auftritt, wird AbatractEndPoint.processSocket aufgerufen, um den Lesevorgang processSocket(attachment, SocketEvent.OPEN_READ, true) auszuführen. Wenn im Kanal, der SelectionKey entspricht, ein Schreibereignis auftritt, wird processSocket(attachment, SocketEvent.OPEN_WRITE, true) ausgeführt; Lesen ist wichtiger als Schreiben. Die Socket-Ereignisverarbeitung ruft die Methode processSocket von AbatractEndPoint auf.

geschützter void processKey(SelectionKey sk, NioSocketWrapper-Anhang) {
	     versuchen {
	         if (schließen) {
	             //Wenn Poller geschlossen ist, brechen Sie den Schlüssel ab
	             abgebrochener Schlüssel (sk);
	         } sonst wenn (sk.isValid() && Anhang != null) {
	             wenn (sk.isReadable() || sk.isWritable()) {
	                 if (attachment.getSendfileData() != null) {
	                     processSendfile(sk, Anhang, false);
	                 } anders {
	                     unreg(sk, Anhang, sk.readyOps());
	                     Boolescher Wert closeSocket = false;
	                     // Lesen geht vor Schreiben
	                     // Lesen ist besser als Schreiben // Wenn der Kanal, der dem SelectionKey entspricht, zum Lesen bereit ist // dann lese den NioSocketWrapper if (sk.isReadable()) {
	                         wenn (!processSocket(attachment, SocketEvent.OPEN_READ, true)) {
	                             : Schließen Sie den Socket nicht.
	                         }
	                     }
	                     // Wenn der Kanal, der dem SelectionKey entspricht, zum Schreiben bereit ist // In NioSocketWrapper schreiben if (!closeSocket && sk.isWritable()) {
	                         wenn (!processSocket(attachment, SocketEvent.OPEN_WRITE, true)) {
	                             : Schließen Sie den Socket nicht.
	                         }
	                     }
	                     if (Socket schließen) {
	                         //Wenn es bereits geschlossen ist, brechen Sie den Schlüssel ab
	                         abgebrochener Schlüssel (sk);
	                     }
	                 }
	             }
	             
}

Die Methode AbatractEndPoint.processSocket ruft zuerst die Klasse SocketProcessor aus dem Cache ab. Wenn im Cache kein SocketProcessor vorhanden ist, wird einer erstellt. Die Schnittstelle SocketProcessorBase entspricht NioEndPoint.SocketProcessor, also Worker. Legen Sie die entsprechende SocketProcessor-Klasse zur Ausführung in den Thread-Pool.

 öffentlicher boolescher ProzessSocket(SocketWrapperBase<S> socketWrapper,
                                 SocketEvent-Ereignis, Boolescher Dispatch) {

	// Den Socket-Prozessor abrufen // Der Connector hat das Protokoll im Konstruktor angegeben: org.apache.coyote.http11.Http11NioProtocol.
	SocketProcessorBase<S> sc = processorCache.pop();
	wenn (sc == null) {
	// Wenn nicht, erstellen Sie einen Socket-Handler. Geben Sie beim Erstellen SocketWrapper und Socket-Ereignisse an.
	    sc = createSocketProcessor(socketWrapper, Ereignis);
	} anders {
	    sc.reset(socketWrapper, Ereignis);
	}
	//Die Socket-Verarbeitung wird an den Thread-Pool übergeben.
	Executor Executor = getExecutor();
	wenn (Dispatch und Executor != null) {
	    Executor.execute(sc);
	} anders {
	    sc.run();
	}

(5) NioEndPoint.NioSocketWrapper ist die Kapselungsklasse und Erweiterungsklasse von Socket, die Socket mit anderen Objekten verknüpft.

 öffentliche statische Klasse NioSocketWrapper erweitert SocketWrapperBase<NioChannel> {
 		privater endgültiger NioSelectorPool-Pool;

        privater Poller poller = null; // Polling-Poller 
        private int InteressenOps = 0;
        privater CountDownLatch readLatch = null;
        privater CountDownLatch writeLatch = null;
        private flüchtige SendfileData sendfileData = null;
        privates flüchtiges langes letztes Lesen = System.currentTimeMillis();
        privates flüchtiges langes letztes Schreiben = letztes Lesen;
        privater flüchtiger Boolescher Wert geschlossen = false;

(6) NioEndPoint.SocketProcessor (Worker) erbt die Runnable-Schnittstelle und ist für die Verarbeitung verschiedener Ereignisse des Sockets verantwortlich. Leseereignisse, Schreibereignisse, Stoppzeit, Timeout-Ereignisse, Trennungsereignisse, Fehlerzeit, Verbindungsfehlerereignisse.

Bildbeschreibung hier einfügen

Die doRun-Methode von SocketProcessor wird gemäß SocketState verarbeitet. Wenn SocketState STOP, DISCONNECT oder ERROR ist, wird es geschlossen. Das Selector-Ereignis, das SocketWrapperBase entspricht, wird vom angegebenen Handler-Prozessor verarbeitet.

@Überschreiben
 geschützt void doRun() {
     NioChannel-Socket = socketWrapper.getSocket();
     SelectionKey-Schlüssel = socket.getIOChannel().keyFor(socket.getPoller().getSelector());

     versuchen {
         int Handshake = -1;

         versuchen {
             wenn (Schlüssel != null) {
                 wenn (socket.isHandshakeComplete()) {
                     // Unabhängig davon, ob der Handshake erfolgreich war und kein TLS-Handshake (verschlüsselt) erforderlich ist, lassen Sie den Prozessor die Kombination aus Socket und Ereignis verarbeiten.
                     Handshake = 0;
                 } sonst wenn (Ereignis == SocketEvent.STOP || Ereignis == SocketEvent.DISCONNECT ||
                         Ereignis == SocketEvent.ERROR) {
                     // Wenn der TLS-Handshake nicht abgeschlossen werden kann, wird dies als ein TLS-Handshake-Fehler betrachtet.
                     Handshake = -1;
                 } anders {
                     Handshake = Socket.Handshake (Schlüssel.ist lesbar (), Schlüssel.ist schreibbar ();
                     // Der Handshake-Prozess liest/schreibt von/in die
                     // Socket. Status kann daher einmal OPEN_WRITE sein
                     // der Handshake wird abgeschlossen. Der Handshake
                     // passiert, wenn der Socket geöffnet wird, also der Status
                     // muss nach Abschluss immer OPEN_READ sein.
                     // Es ist in Ordnung, dies immer festzulegen, da es nur verwendet wird, wenn
                     // der Handshake ist abgeschlossen.
                     // Beim Handshake zum Lesen/Schreiben vom/zum Socket sollte der Status OPEN_WRITE sein, sobald der Handshake abgeschlossen ist.
                     // Der Handshake findet statt, wenn der Socket geöffnet wird, daher muss der Status nach Abschluss immer OPEN_READ sein.
                     // Es ist in Ordnung, diese Option immer festzulegen, da sie nur verwendet wird, wenn der Handshake abgeschlossen ist.
                     Ereignis = SocketEvent.OPEN_READ;
                 }
             }
         } Fang (IOException x) {
             Handshake = -1;
             if (log.isDebugEnabled()) log.debug("Fehler beim SSL-Handshake", x);
         } Fang (CancelledKeyException ckx) {
             Handshake = -1;
         }
         wenn (Handshake == 0) {
             SocketState-Status = SocketState.OPEN;
             // Verarbeite die Anfrage von diesem Socket
             wenn (Ereignis == null) {
                 // Rufen Sie den Handler zur Verarbeitung auf.
                 // Der Standard-Handler von NioEndPoint ist Http11 // Der Handler hier ist AbstractProtocol.ConnectionHandler
                 // Die Einstellungsmethode dieses Handlers ist:
                 // Legen Sie zunächst im Konstruktor der Connector-Klasse den Standard-ProtocolHandler auf org.apache.coyote.http11.Http11NioProtocol fest.
                 // Die Handler-Klasse ConnectionHandler wird im Konstruktor von AbstractHttp11Protocol erstellt
                 Status = getHandler().Prozess(socketWrapper, SocketEvent.OPEN_READ);
             } anders {
                 Status = getHandler().Prozess(socketWrapper, Ereignis);
             }
             // Wenn der zurückgegebene Status SocketState ist, schließe die Verbindung if (state == SocketState.CLOSED) {
                 schließen (Buchse, Schlüssel);
             }
         } sonst wenn (Handshake == -1) {
             getHandler().process(socketWrapper, SocketEvent.CONNECT_FAIL);
             schließen (Buchse, Schlüssel);
         } sonst wenn (Handshake == Auswahlschlüssel.OP_READ) {
             // Wenn es SelectionKey.OP_READ ist, also ein Leseereignis, setzen Sie die OP_READ-Zeit auf socketWrapper
             socketWrapper.registerReadInterest();
         } sonst wenn (Handshake == Auswahlschlüssel.OP_WRITE) {
             // Wenn es SelectionKey.OP_WRITE ist, also ein Leseereignis, setzen Sie das OP_WRITE-Ereignis auf socketWrapper
             socketWrapper.registerWriteInterest();
         }

2. Verbindungshandler

Bildbeschreibung hier einfügen

(1) ConnectionHandler wird verwendet, um den entsprechenden Engine-Prozessor basierend auf der Socket-Verbindung zu finden.

Oben ist die doRun-Methode von SocketProcessor, die getHandler().process(socketWrapper, SocketEvent.OPEN_READ); ausführt. Die Prozessmethode sucht zuerst im Map-Cache nach einem entsprechenden Prozessor für den aktuellen Socket. Wenn nicht, sucht sie im wiederverwendbaren Prozessorstapel nach einem. Wenn nicht, erstellt sie einen entsprechenden Prozessor, ordnet den neu erstellten Prozessor dann dem Socket zu und speichert ihn in der Map der Verbindung. Nachdem das Prozessorobjekt zu einem beliebigen Zeitpunkt abgerufen wurde, lautet die Prozessmethode des Prozessors state = processor.process(wrapper, status);

geschützte statische Klasse ConnectionHandler<S> implementiert AbstractEndpoint.Handler<S> {

        privates endgültiges AbstractProtocol<S>-Proto;
        private final RequestGroupInfo global = neue RequestGroupInfo();
        private final AtomicLong registerCount = neues AtomicLong(0);
        // Schließlich wurde diese Sammlung gefunden und eine Verbindung zwischen dem Socket und dem Prozessor hergestellt. // Jeder gültige Link wird hier zwischengespeichert, um eine Verbindung herzustellen und eine geeignete Prozessorimplementierung für die Anforderungsverarbeitung auszuwählen.
        private finale Map<S, Prozessor>-Verbindungen = neue ConcurrentHashMap<>();
        // Wiederverwertbarer Prozessorstapel private final RecycledProcessors recycledProcessors = new RecycledProcessors(this);

		
  		@Überschreiben
        öffentlicher SocketState-Prozess (SocketWrapperBase<S>-Wrapper, SocketEvent-Status) {
            wenn (getLog().isDebugEnabled()) {
                getLog().debug(sm.getString("abstractConnectionHandler.process",
                        wrapper.getSocket(), status));
            }
            wenn (Wrapper == null) {
                // Wrapper == null bedeutet, dass der Socket geschlossen wurde und daher keine Aktion erforderlich ist.
                SocketState.CLOSED zurückgeben;
            }
            //Holen Sie sich das Socket-Objekt S im Wrapper socket = wrapper.getSocket();
            //Den zum Sockel passenden Prozessor aus dem Map-Puffer holen.
            Prozessor Prozessor = Verbindungen.get(Socket);
            wenn (getLog().isDebugEnabled()) {
                getLog().debug(sm.getString("abstractConnectionHandler.connectionsGet",
                        Prozessor, Sockel));
            }

            // Timeouts werden auf einem dedizierten Thread berechnet und dann
            // versendet. Aufgrund von Verzögerungen im Versandprozess ist die
            // Timeout ist möglicherweise nicht mehr erforderlich. Überprüfen Sie hier und vermeiden Sie
            // unnötige Verarbeitung.

            // Das Timeout wird auf einem dedizierten Thread berechnet und dann geplant.
            // Aufgrund von Verzögerungen im Planungsprozess ist das Timeout möglicherweise nicht mehr erforderlich. Klicken Sie hier, um unnötige Verarbeitung zu vermeiden.
            wenn (SocketEvent.TIMEOUT == status &&
                    (Prozessor == null ||
                            !processor.isAsync() und !processor.isUpgrade() ||
                            Prozessor.isAsync() && !Prozessor.checkAsyncTimeoutGeneration())) {
                // Dies ist praktisch ein NO-OP
                SocketState.OPEN zurückgeben;
            }
            // Wenn der Map-Cache einen Prozessor hat, der mit dem Socket verknüpft ist if (processor != null) {
                // Stellen Sie sicher, dass kein asynchrones Timeout ausgelöst wird
                // Stellen Sie sicher, dass kein asynchrones Timeout ausgelöst wird getProtocol().removeWaitingProcessor(processor);
            } sonst wenn (status == SocketEvent.DISCONNECT || status == SocketEvent.ERROR) {
                // Nichts zu tun. Endpunkt hat eine Schließung angefordert und es gibt keine
                // Es ist kein Prozessor mehr mit diesem Sockel verbunden.
                // Das SocketEvent-Ereignis ist geschlossen oder die SocketEvent-Zeit ist falsch. Zu diesem Zeitpunkt ist kein Vorgang erforderlich.
                // Der Endpunkt benötigt ein GESCHLOSSEN-Signal und es besteht keine Verbindung mehr, die mit diesem Socket verknüpft ist. return SocketState.CLOSED;
            }

            ContainerThreadMarker.set();

            versuchen {
                // Der Map-Cache enthält nicht den Prozessor, der diesem Socket zugeordnet ist, if (processor == null) {
                    Zeichenfolge ausgehandeltesProtokoll = Wrapper.getNegotiatedProtocol();
                    // OpenSSL gibt normalerweise null zurück, während JSSE normalerweise
                    // gibt "" zurück, wenn kein Protokoll ausgehandelt wurde
                    // OpenSSL gibt normalerweise null zurück, während JSSE normalerweise "" zurückgibt, wenn kein Protokoll ausgehandelt wurde
                    wenn (negotiatedProtocol != null und negotiationProtocol.length() > 0) {
                        // Holen Sie sich das Verhandlungsprotokoll UpgradeProtocol upgradeProtocol = getProtocol().getNegotiatedProtocol(negotiatedProtocol);
                        wenn (upgradeProtocol != null) {
                            // Das Upgrade-Protokoll ist leer. Prozessor = upgradeProtocol.getProcessor(Wrapper, getProtocol().getAdapter());
                            wenn (getLog().isDebugEnabled()) {
                                getLog().debug(sm.getString("abstractConnectionHandler.processorCreate", Prozessor));
                            }
                        } sonst wenn (negotiatedProtocol.equals("http/1.1")) {
                            // Das Standardprotokoll wurde explizit ausgehandelt.
                            // Besorgen Sie sich unten einen Prozessor.
                        } anders {
                            // ZU TUN:
                            // Der ALPN-Rückruf von OpenSSL 1.0.2 unterstützt nicht
                            // Der Handshake schlägt mit einem Fehler fehl, wenn nein
                            // Protokoll kann ausgehandelt werden. Daher müssen wir
                            // Die Verbindung schlägt hier fehl. Sobald dies behoben ist,
                            // Ersetzen Sie den folgenden Code durch den auskommentierten
                            // blockieren.
                            wenn (getLog().isDebugEnabled()) {
                                getLog().debug(sm.getString("abstractConnectionHandler.negotiatedProcessor.fail",
                                        ausgehandeltesProtokoll));
                            }
                            gibt SocketState.CLOSED zurück;
                            /*
                             * Um den obigen Code zu ersetzen, sobald OpenSSL 1.1.0
                             * gebraucht.
                            // Prozessor konnte nicht erstellt werden. Dies ist ein Fehler.
                            neue IllegalStateException werfen(sm.getString(
                                    "abstractConnectionHandler.negotiatedProcessor.fail",
                                    ausgehandeltesProtokoll));
                            */
                        }
                    }
                }
                // Nach den obigen Vorgängen ist der Prozessor immer noch null.
                if (Prozessor == null) {
                    // Holen Sie sich den Prozessor aus den wiederverwertbaren Prozessoren von recycledProcessors
                    Prozessor = recycelteProzessoren.pop();
                    wenn (getLog().isDebugEnabled()) {
                        getLog().debug(sm.getString("abstractConnectionHandler.processorPop", Prozessor));
                    }
                }
                if (Prozessor == null) {
                    // Einen Prozessor erstellen processor = getProtocol().createProcessor();
                    Register (Prozessor);
                    wenn (getLog().isDebugEnabled()) {
                        getLog().debug(sm.getString("abstractConnectionHandler.processorCreate", Prozessor));
                    }
                }
                Prozessor.setSslSupport(
                        wrapper.getSslSupport(getProtocol().getClientCertProvider()));

                // Den Sockel dem Prozessor zuordnen.
                Verbindungen.put(Socket, Prozessor);

                SocketState-Status = SocketState.GESCHLOSSEN;
                Tun {
                    // Rufen Sie die Prozessmethode des Prozessors auf.
                    Zustand = Prozessor.Prozess(Wrapper, Status);

                    // Die Prozessmethode des Prozessors gibt den Upgrade-Status zurück, wenn (Status == SocketState.UPGRADING) {
                        // Den HTTP-Upgrade-Handler abrufen
                        // HTTP-Upgrade-Handle abrufen UpgradeToken upgradeToken = processor.getUpgradeToken();
                        // Restliche Eingabe abrufen
                        // Verbleibende Eingabe abrufen ByteBuffer leftOverInput = processor.getLeftoverInput();
                        if (upgradeToken == null) {
                            // Direkte HTTP/2-Verbindung vorausgesetzt
                            UpgradeProtocol upgradeProtocol = getProtocol().getUpgradeProtocol("h2c");
                            wenn (upgradeProtocol != null) {
                                // Den Http11-Prozessor zur Wiederverwendung freigeben
                                Freigabe (Prozessor);
                                // Den Upgrade-Prozessor erstellen
                                Prozessor = upgradeProtocol.getProcessor(Wrapper, getProtocol().getAdapter());
                                Wrapper.unRead(leftOverInput);
                                // Mit dem Prozessor über die Verbindung verknüpfen
                                Verbindungen.put(Socket, Prozessor);
                            } anders {
                                wenn (getLog().isDebugEnabled()) {
                                    getLog().debug(sm.getString(
                                            "abstractConnectionHandler.negotiatedProcessor.fail",
                                            "h2c"));
                                }
                                //Schleife verlassen und entsprechende Bereinigung auslösen
                                Zustand = SocketState.GESCHLOSSEN;
                            }
                        } anders {
                            HttpUpgradeHandler httpUpgradeHandler = upgradeToken.getHttpUpgradeHandler();
                            // Den Http11-Prozessor zur Wiederverwendung freigeben
                            Freigabe (Prozessor);
                            // Den Upgrade-Prozessor erstellen
                            Prozessor = getProtocol().createUpgradeProcessor(Wrapper, UpgradeToken);
                            wenn (getLog().isDebugEnabled()) {
                                getLog().debug(sm.getString("abstractConnectionHandler.upgradeCreate",
                                        Prozessor, Wrapper));
                            }
                            wrapper.unRead(leftOverInput);
                            // Mit dem Prozessor über die Verbindung verknüpfen
                            Verbindungen.put(Socket, Prozessor);
                            // Initialisieren Sie den Upgrade-Handler (der möglicherweise auslöst
                            // einige IO mit dem neuen Protokoll, weshalb die Zeilen
                            //oben sind erforderlich)
                            // Dieser Cast sollte sicher sein. Wenn er fehlschlägt, wird der Fehler
                            // Die Handhabung des umgebenden Try/Catch wird erledigt
                            // Es.
                            if (upgradeToken.getInstanceManager() == null) {
                                httpUpgradeHandler.init((WebConnection) Prozessor);
                            } anders {
                                ClassLoader oldCL = upgradeToken.getContextBind().bind(false, null);
                                versuchen {
                                    httpUpgradeHandler.init((WebConnection) Prozessor);
                                Endlich
                                    upgradeToken.getContextBind().unbind(false, oldCL);
                                }
                            }
                        }
                    }
                } während (Status == SocketState.UPGRADING);	

(2) Am Beispiel des Http11-Protokolls wird Http11Processor ausgeführt. Die übergeordnete Klasse von Http11Processor, AbstractProcessorLight, implementiert die Prozessmethode. Der Prozess ruft die Service-Vorlagenmethode auf, die von Http11Processor implementiert wird. Die wichtigste Operation der Servicemethode ist die Ausführung getAdapter().service(request, response);

@Überschreiben
    öffentlicher SocketState-Dienst (SocketWrapperBase<?> socketWrapper)
            wirft IOException {
		// n Zeilen oben werden ausgelassen // ​​Rufen Sie die Servicemethode von Coyote auf getAdapter().service(request, response);
		 // Die folgenden n Zeilen werden weggelassen

3. Kojote

Denken Sie daran, dass CoyoteAdapter in der initInternal-Methode von Connector erstellt wird.

@Überschreiben
    öffentlicher SocketState-Dienst (SocketWrapperBase<?> socketWrapper)
            wirft IOException {
		// n Zeilen oben werden ausgelassen // ​​Rufen Sie die Servicemethode von Coyote auf getAdapter().service(request, response);
		 // Die folgenden n Zeilen werden weggelassen

Die Funktion von Coyote besteht darin, coyote.Request und coyote.Rsponse in HttpServletRequest und HttpServletRsponse umzuwandeln. Da sich der Connector während der Initialisierung selbst in den CoyoteAdapter einfügt, kann der Dienst direkt über connector.getService() abgerufen werden. Anschließend wird der Verantwortungskettenmodus vom Dienst zur Verarbeitung aufgerufen.

@Überschreiben
    öffentlicher SocketState-Dienst (SocketWrapperBase<?> socketWrapper)
            wirft IOException {
		// n Zeilen oben werden ausgelassen // ​​Rufen Sie die Servicemethode von Coyote auf getAdapter().service(request, response);
		 // Die folgenden n Zeilen werden weggelassen

4. Muster der Container-Verantwortungskette

Als nächstes folgt das Verantwortungskettenmodell, das bei StandardEngine beginnt. Führen Sie zunächst den Verantwortungskettenmodus von StandardEngine aus, um die entsprechende Engine zu finden. Die entsprechende Engine findet dann den entsprechenden Kontext über den Verantwortungskettenmodus, bis StandardWrapperValve gefunden wird. Abschließend wird die Invoke-Methode von StandardWrapperValve ausgeführt. Überprüfen Sie zunächst, ob Context und Wrapper nicht verfügbar sind. Wenn sie verfügbar sind und Servelt nicht initialisiert wurde, führen Sie den Initialisierungsvorgang aus. Im Single-Thread-Modus wird der zuvor erstellte Servelt direkt zurückgegeben. Im Multi-Thread-Modus wird zuerst ein Servelt-Objekt erstellt und zurückgegeben.

@Überschreiben
    öffentliches Finale void invoke (Anfrage Anfrage, Antwort Antwort)
            wirft IOException, ServletException {
        // Initialisieren Sie die benötigten lokalen Variablen boolean unavailable = false;
        Wurfbar, Wurfbar = null;
        // Dies sollte ein Anforderungsattribut sein …
        lange t1 = System.currentTimeMillis();
        // Atomare Klasse AtomicInteger, CAS-Operation, die die Anzahl der Anfragen angibt.
        requestCount.incrementAndGet();
        StandardWrapper-Wrapper = (StandardWrapper) getContainer();
        Servlet-Servlet = null;
        Kontext Kontext = (Kontext) wrapper.getParent();

        // Überprüfen Sie, ob die aktuelle Context-Anwendung als nicht verfügbar markiert wurde if (!context.getState().isAvailable()) {
            //Wenn die aktuelle Anwendung nicht verfügbar ist, melden Sie einen 503-Fehler.
            Antwort.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                    sm.getString("standardContext.isUnavailable"));
            nicht verfügbar = wahr;
        }

        // Prüfen, ob der Servelt als nicht verfügbar markiert ist, if (!unavailable && wrapper.isUnavailable()) {
            container.getLogger().info(sm.getString("standardWrapper.istNichtverfügbar",
                    wrapper.getName()));
            lange verfügbar = Wrapper.getAvailable();
            if ((verfügbar > 0L) && (verfügbar < Long.MAX_VALUE)) {
                response.setDateHeader("Retry-After", verfügbar);
                Antwort.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
                        sm.getString("standardWrapper.istNichtverfügbar",
                                wrapper.getName()));
            } sonst wenn (verfügbar == Long.MAX_VALUE) {
                Antwort.sendError(HttpServletResponse.SC_NOT_FOUND,
                        sm.getString("standardWrapper.notFound",
                                wrapper.getName()));
            }
            nicht verfügbar = wahr;
        }
        //Servelt wird beim ersten Aufruf initialisiert try {
            wenn (!nicht verfügbar) {
                // Wenn Servelt zu diesem Zeitpunkt noch nicht initialisiert wurde, weisen Sie eine Servelt-Instanz zur Bearbeitung der Anforderung zu.
                servlet = Wrapper.Zuweisen();
            }
        /// Code auslassen...........................................
        // // Erstellen Sie eine Filterkette für die Anfrage. Nachdem die Filterkette ausgeführt wurde, Servelt
        Anwendungsfilterkette Filterkette =
                ApplicationFilterFactory.createFilterChain(Anfrage, Wrapper, Servlet);

        // Rufe die Filterkette für diese Anfrage auf
        // HINWEIS: Dies ruft auch die service()-Methode des Servlets auf
        versuchen {
            wenn ((servlet != null) und (filterChain != null)) {
                // Bei Bedarf die Ausgabe schlucken
                wenn (Kontext.getSwallowOutput()) {
                    versuchen {
                        SystemLogHandler.startCapture();
                        wenn (request.isAsyncDispatching()) {
                            request.getAsyncContextInternal().doInternalDispatch();
                        } anders {
                            //Filterkette aufrufen filterChain.doFilter(request.getRequest(),
                                    Antwort.getResponse());
                        }
        /// Code auslassen...........................................
        

Dies ist das Ende dieses Artikels über die Analyse des Tomcat-Quellcodes sowie Webanforderungen und -verarbeitung. Weitere Inhalte zu Tomcats Webanforderungen und -verarbeitung finden Sie in den vorherigen Artikeln von 123WORDPRESS.COM oder in den folgenden verwandten Artikeln. Ich hoffe, dass jeder 123WORDPRESS.COM in Zukunft unterstützen wird!

Das könnte Sie auch interessieren:
  • Betrachten des Threadmodells von Tomcat aus der Connector-Komponente – BIO-Modus (empfohlen)
  • Tomcat verwendet Thread-Pool zur Verarbeitung gleichzeitiger Remote-Anfragen
  • Detaillierte Erläuterung des Thread-Modells von Tomcat zur Verarbeitung von Anforderungen

<<:  So beheben Sie die durch MySQL DDL verursachte Synchronisierungsverzögerung

>>:  Erfahren Sie in einem Artikel mehr über JavaScript-Closure-Funktionen

Artikel empfehlen

Echarts-Tutorial zur Implementierung von Baumdiagrammen

Treemaps dienen vor allem der Visualisierung baum...

React-Methode zum Anzeigen von Daten auf Seiten

Inhaltsverzeichnis Übergeordnete Komponente „list...

Natives JS zur Implementierung der E-Mail-Eingabeaufforderung im Anmeldefeld

Dieser Artikel beschreibt eine native JS-Implemen...

Lernen Sie die Grundlagen der JavaScript-DOM-Operationen in einem Artikel

DOM-Konzepte DOM: Dokumentobjektmodell: Das Dokum...

Kann CSS auf diese Weise verwendet werden? Die Kunst wunderlicher Farbverläufe

Im vorherigen Artikel – Der Charme einer Zeile CS...

Verwenden Sie js, um js-Funktionen in Iframe-Seiten aufzurufen

In letzter Zeit habe ich jeden Tag an meinen Absch...

So überwachen Sie mehrere JVM-Prozesse in Zabbix

1. Szenariobeschreibung: Unsere Umgebung verwende...

So erstellen Sie einen Flammeneffekt mit CSS

Unten beginnt der Haupttext. 123WORDPRESS.COM Her...

HTML implementiert die Funktion zur Erkennung der Eingabevervollständigung

Verwenden Sie „onInput(event)“, um festzustellen,...

Zwei Implementierungslösungen für die Vuex-Datenpersistenz

Inhaltsverzeichnis Geschäftsanforderungen: Lösung...

Wann sollte man Map anstelle einfacher JS-Objekte verwenden?

Inhaltsverzeichnis 1. Map akzeptiert jeden Schlüs...