Vorwort Durch meine vorherige Tomcat-Artikelserie glaube ich, dass die Studenten, die meinen Blog lesen, ein klareres Verständnis von Tomcat haben sollten. In den vorherigen Blogs haben wir besprochen, wie Tomcat im SpringBoot-Framework gestartet wird, wie die internen Komponenten von Tomcat entworfen sind und wie Anfragen fließen. Lassen Sie uns nun über Tomcats asynchrones Servlet sprechen, wie Tomcat asynchrones Servlet implementiert und die Verwendungsszenarien von asynchronem Servlet. Praktisches asynchrones Servlet Wir verwenden direkt das SpringBoot-Framework, um ein Servlet zu implementieren. Hier zeigen wir nur den Servlet-Code: @WebServlet(urlPatterns = "/async",asyncSupported = true) @Slf4j öffentliche Klasse AsyncServlet erweitert HttpServlet { ExecutorService executorService = Executors.newSingleThreadExecutor(); @Überschreiben geschützt void doGet(HttpServletRequest req, HttpServletResponse resp) wirft ServletException, IOException { //Asynchron starten und den asynchronen Kontext abrufen final AsyncContext ctx = req.startAsync(); // Thread-Pool asynchrone Ausführung übermitteln executorService.execute(new Runnable() { @Überschreiben öffentliche Leere ausführen() { versuchen { log.info("Der asynchrone Dienst ist zur Ausführung bereit"); //Zeitaufwändige Aufgaben simulieren Thread.sleep(10000L); ctx.getResponse().getWriter().print("asynchrones Servlet"); log.info("asynchroner Dienst ausgeführt"); } Fang (IOException e) { e.printStackTrace(); } Fang (UnterbrocheneAusnahme e) { e.printStackTrace(); } //Schließlich wird der Rückruf abgeschlossen, nachdem die Ausführung abgeschlossen ist. ctx.komplett(); } }); } Der obige Code implementiert ein asynchrones Servlet und implementiert Nachdem wir eine Anfrage gesendet haben, sehen wir, dass die Seite antwortet und dass die Anfrage 10,05 Sekunden dauert, sodass unser Servlet normal läuft. Einige Studenten werden sicherlich fragen: Ist das nicht ein asynchrones Servlet? Was bringt es, wenn Ihre Reaktionszeit nicht schneller ist? Ja, unsere Antwortzeit kann nicht beschleunigt werden, es hängt immer noch von unserer Geschäftslogik ab, aber nach unserer asynchronen Servlet-Anforderung können wir, basierend auf der asynchronen Ausführung des Geschäfts, sofort zurückkehren, d. h. Tomcat-Threads können sofort recycelt werden. Standardmäßig gibt es 10 Kernthreads von Tomcat und die maximale Anzahl von Threads beträgt 200. Wir können Threads rechtzeitig recyceln, was bedeutet, dass wir mehr Anforderungen verarbeiten und unseren Durchsatz erhöhen können, was auch die Hauptfunktion des asynchronen Servlets ist. Interna asynchroner Servlets Nachdem wir die Rolle des asynchronen Servlets verstanden haben, schauen wir uns an, wie Tomcat das erste asynchrone Servlet ist. Tatsächlich besteht die Hauptkernlogik des obigen Codes aus zwei Teilen: öffentliche AsyncContext startAsync(ServletRequest Anfrage, ServletResponse-Antwort) { wenn (!isAsyncSupported()) { IllegalStateException ise = neue IllegalStateException(sm.getString("request.asyncNotSupported")); log.warnen(sm.getString("coyoteRequest.noAsync", : StringUtils.join(getNonAsyncClassNames())), ise); wirf Ise; } wenn (asyncContext == null) { asyncContext = neuer AsyncContextImpl(dies); } asyncContext.setStarted(getContext(), Anfrage, Antwort, Anfrage==getRequest() und Antwort==getResponse().getResponse()); asyncContext.setTimeout(getConnector().getAsyncTimeout()); gibt asynchronen Kontext zurück; } Wir haben festgestellt Schauen wir uns die Logik von öffentliche Leere komplett() { wenn (log.isDebugEnabled()) { logDebug("abgeschlossen"); } überprüfen(); request.getCoyoteRequest().action(ActionCode.ASYNC_COMPLETE, null); } //Klasse: AbstractProcessor öffentliche final void Aktion(Aktionscode Aktionscode, Objektparameter) { Fall ASYNC_COMPLETE: { : Löscht Dispatches(); wenn (asyncStateMachine.asyncComplete()) { verarbeitenSocketEvent(SocketEvent.OPEN_READ, true); } brechen; } } //Klasse: AbstractProcessor geschützt void processSocketEvent(SocketEvent-Ereignis, boolean dispatch) { SocketWrapperBase<?> socketWrapper = getSocketWrapper(); wenn (socketWrapper != null) { socketWrapper.processSocket(Ereignis, Versand); } } //Klasse: AbstractEndpoint öffentlicher boolescher ProzessSocket(SocketWrapperBase<S> socketWrapper, SocketEvent-Ereignis, Boolescher Dispatch) { //Einigen Code weglassen SocketProcessorBase<S> sc = null; if (ProzessorCache != null) { sc = ProzessorCache.pop(); } wenn (sc == null) { sc = createSocketProcessor(socketWrapper, Ereignis); } anders { sc.reset(socketWrapper, Ereignis); } Executor Executor = getExecutor(); wenn (Dispatch und Executor != null) { Executor.execute(sc); } anders { sc.run(); } gibt true zurück; } Daher wird hier die Klasse: AbstractProcessorLight öffentlicher SocketState-Prozess (SocketWrapperBase<?> socketWrapper, SocketEvent-Status) wirft IOException { //Teil des Durchmessers weglassen SocketState-Status = SocketState.GESCHLOSSEN; Iterator<DispatchType> dispatches = null; Tun { wenn (dispatches != null) { DispatchType nextDispatch = dispatches.next(); Status = Versand (nextDispatch.getSocketStatus()); } sonst wenn (status == SocketEvent.DISCONNECT) { } sonst wenn (isAsync() || isUpgrade() || Status == SocketState.ASYNC_END) { Zustand = Versand(Status); wenn (Status == SocketState.OPEN) { Status = Dienst(SocketWrapper); } } sonst wenn (status == SocketEvent.OPEN_WRITE) { Zustand = SocketState.LONG; } sonst wenn (status == SocketEvent.OPEN_READ) { Status = Dienst(SocketWrapper); } anders { Zustand = SocketState.GESCHLOSSEN; } } während (Status == SocketState.ASYNC_END || versendet != null und Status != SocketState.CLOSED); Rückgabezustand; } Dieser Teil ist der entscheidende Punkt. öffentliches Boolean asyncDispatch(org.apache.coyote.Request req, org.apache.coyote.Response res, SocketEvent-Status) löst Exception aus { //Code weglassen Request request = (Request) req.getNote(ADAPTER_NOTES); Antwort Antwort = (Antwort) res.getNote(ADAPTER_NOTES); Boolescher Erfolg = wahr; AsyncContextImpl asyncConImpl = request.getAsyncContextInternal(); versuchen { wenn (!request.isAsync()) { Antwort.setSuspended(false); } wenn (status==SocketEvent.TIMEOUT) { wenn (!asyncConImpl.timeout()) { asyncConImpl.setErrorState(null, false); } } sonst wenn (status==SocketEvent.ERROR) { } wenn (!request.isAsyncDispatching() && request.isAsync()) { WriteListener writeListener = res.getWriteListener(); : LesenListener lesenListener = req.getReadListener(); wenn (writeListener != null und status == SocketEvent.OPEN_WRITE) { ClassLoader alteCL = null; versuchen { alteCL = request.getContext().bind(false, null); res.onWritePossible(); //Hier die Browserantwort ausführen und Daten schreiben, wenn (request.isFinished() && req.sendAllDataReadEvent() && readListener != null) { readListener.onAllDataRead(); } } fangen (Wurfbares t) { Endlich request.getContext().unbind(false, oldCL); } } } } // Hier wird beurteilt, dass Asynchronität im Gange ist, was bedeutet, dass dies kein Rückruf einer Vervollständigungsmethode ist, sondern eine normale asynchrone Anforderung, und der Container wird weiterhin aufgerufen. wenn (request.isAsyncDispatching()) { Connector.getService().getContainer().getPipeline().getFirst().aufrufen( Anfrage, Antwort); Throwable t = (Throwable) Anfrage.getAttribute(RequestDispatcher.ERROR_EXCEPTION); wenn (t != null) { asyncConImpl.setErrorState(t, true); } } //Beachten Sie, dass hier im Falle eines Timeouts oder Fehlers request.isAsync() false zurückgibt, um den Fehler schnellstmöglich an den Client auszugeben. wenn (!request.isAsync()) { //Dies ist auch die Ausgabelogik request.finishRequest(); Antwort.finishResponse(); } //Anfrage und Antwort zerstören wenn (!Erfolg || !request.isAsync()) { updateWrapperErrorCount(Anfrage, Antwort); Anfrage.recycle(); antwort.recycle(); } } Erfolg zurückgeben; } Der obige Code ist die letzte Einige Studenten sagen hier vielleicht: „Ich weiß, dass nach Abschluss der asynchronen Ausführung durch den Aufruf postParseSuccess = postParseRequest(Anforderung, Anfrage, Antwort); //Code weglassen if (postParseSuccess) { Anfrage.setAsyncSupported( Connector.getService().getContainer().getPipeline().isAsyncSupported()); Connector.getService().getContainer().getPipeline().getFirst().aufrufen( Anfrage, Antwort); } wenn (request.isAsync()) { asynchron = wahr; } anders { //Daten an den Client ausgeben request.finishRequest(); Antwort.finishResponse(); wenn (!async) { updateWrapperErrorCount(Anfrage, Antwort); //Anfrage und Antwort zerstören Anfrage.recycle(); antwort.recycle(); } Nach dem Aufruf Warum die @EnableAsync-Annotation von Spring Boot kein asynchrones Servlet ist Da ich bei der Vorbereitung dieses Artikels viele Informationen gesucht habe, habe ich festgestellt, dass viele Materialien zur asynchronen Programmierung mit SpringBoot auf der Annotation @RestController @Slf4j öffentliche Klasse TestController { @Autowired privater TestService-Dienst; @GetMapping("/hallo") öffentlicher Stringtest () { versuchen { log.info("testAsynch Start"); CompletableFuture<String> test1 = service.test1(); CompletableFuture<String> test2 = service.test2(); CompletableFuture<String> test3 = service.test3(); CompletableFuture.allOf(test1, test2, test3); log.info("test1=====" + test1.get()); log.info("test2=====" + test2.get()); log.info("test3=====" + test3.get()); } Fang (UnterbrocheneAusnahme e) { e.printStackTrace(); } Fang (Ausführungsausnahme e) { e.printStackTrace(); } gib "hallo" zurück; } @Service öffentliche Klasse TestService { @Async("asyncExecutor") public CompletableFuture<String> test1() wirft InterruptedException { Thread.sleep(3000L); returniere CompletableFuture.completedFuture("test1"); } @Async("asyncExecutor") public CompletableFuture<String> test2() wirft InterruptedException { Thread.sleep(3000L); returniere CompletableFuture.completedFuture("test2"); } @Async("asyncExecutor") public CompletableFuture<String> test3() wirft InterruptedException { Thread.sleep(3000L); return CompletableFuture.completedFuture("test3"); } } @SpringBootAnwendung @EnableAsync öffentliche Klasse TomcatdebugApplication { öffentliche statische void main(String[] args) { SpringApplication.run(TomcatdebugApplication.class, args); } @Bean(Name = "asyncExecutor") öffentlicher Executor asyncExecutor() { ThreadPoolTaskExecutor Executor = neuer ThreadPoolTaskExecutor(); executor.setCorePoolSize(3); executor.setMaxPoolSize(3); executor.setQueueCapacity(100); executor.setThreadNamePrefix("AsynchThread-"); Executor.initialisieren(); Testamentsvollstrecker zurückgeben; } Hier führe ich es aus und sehe die Wirkung Hier habe ich nach meiner Anforderung einen Haltepunkt gesetzt, bevor ich den Container aufgerufen habe, um die Geschäftslogik auszuführen, und dann nach der Rückkehr einen Haltepunkt gesetzt. Nachdem Die Kernlogik der obigen Analyse besteht darin, dass der Tomcat-Thread, nachdem er Lassen Sie uns über die Verwendungsszenarien des asynchronen Servlets sprechen Was sind nach so vielen Analysen die Anwendungsszenarien für asynchrone Servlets? Tatsächlich können wir es analysieren, indem wir nur einen Punkt erfassen: Asynchrone Servlets verbessern den Durchsatz des Systems und können mehr Anfragen annehmen. Angenommen, Tomcat verfügt im Websystem nicht über genügend Threads und es warten viele Anfragen. Zu diesem Zeitpunkt kann die Optimierung auf Anwendungsebene des Websystems nicht mehr optimiert werden, d. h. die Antwortzeit der Geschäftslogik kann nicht verkürzt werden. Wenn Sie zu diesem Zeitpunkt die Wartezeit des Benutzers verkürzen und den Durchsatz erhöhen möchten, können Sie versuchen, ein asynchrones Servlet zu verwenden. Nehmen wir ein praktisches Beispiel: Wenn wir beispielsweise ein SMS-System erstellen, hat das SMS-System sehr hohe Anforderungen an die Echtzeitleistung, sodass die Wartezeit so kurz wie möglich sein muss und die Sendefunktion tatsächlich dem Bediener zum Senden anvertraut wird, das heißt, wir müssen die Schnittstelle aufrufen. Angenommen, die Parallelität ist sehr hoch, dann ist es zu diesem Zeitpunkt, an dem das Geschäftssystem unsere SMS-Sendefunktion aufruft, möglich, dass unser Tomcat-Thread-Pool aufgebraucht ist und die verbleibenden Anforderungen in der Warteschlange warten. Zu diesem Zeitpunkt erhöht sich die Verzögerung der SMS. Um dieses Problem zu lösen, können wir ein asynchrones Servlet einführen, um mehr SMS-Sendeanforderungen anzunehmen und so die Verzögerung der SMS zu verringern. Zusammenfassen In diesem Artikel habe ich zunächst ein asynchrones Servlet von Hand geschrieben, die Rolle des asynchronen Servlets analysiert und erklärt, wie das asynchrone Servlet in Tomcat implementiert wird. Anschließend habe ich es auch anhand der im Internet beliebten asynchronen SpringBoot-Programmierung erklärt. In Tomcat gibt es kein asynchrones Servlet. Abschließend habe ich über die Verwendungsszenarien asynchroner Servlets gesprochen und die Situationen analysiert, in denen asynchrone Servlets ausprobiert werden können. Das Obige ist der vollständige Inhalt dieses Artikels. Ich hoffe, er wird für jedermanns Studium hilfreich sein. Ich hoffe auch, dass jeder 123WORDPRESS.COM unterstützen wird. Das könnte Sie auch interessieren:
|
>>: Vergleich zweier Implementierungsmethoden der Vue-Dropdown-Liste
Responsive Layoutsysteme sind in den heute gängig...
In diesem Artikelbeispiel wird der spezifische Co...
Im neuesten HTML-Standard gibt es einen Calc-CSS-A...
Wenn Programmierer täglich TypeScript-/JavaScript...
1. Abhängigkeit herunterladen npm installiere @an...
<br />Vor Kurzem hat UCDChina eine Artikelse...
Wirkung: Code: <Vorlage> <div Klasse=&qu...
1. Tools und Bibliotheken installieren # PCRE ist...
Wenn Sie kein Linux-System haben, finden Sie unte...
Erfordern Das Div unter dem Körper ist vertikal z...
1: Installationsbefehl pip install docker-compose...
Wir sollten besser aufpassen, denn die HTML-Poliz...
Was ist ein Primärschlüssel? Ein Primärschlüssel ...
Vor kurzem habe ich an der Entwicklung des ersten...
So installieren Sie MySQL 5.7.18 unter Linux 1. L...