CLOVER🍀

That was when it all began.

Jakarta Servletの非同期処理でディスパッチをいろいろ試してみる(WildFly 35、Tomcat 10.1)

これは、なにをしたくて書いたもの?

前に、Jakarta Servletの非同期処理について扱ってみました。

Jakarta Servletの非同期処理をWildFly 35、Apache Tomcat 10.1で試す - CLOVER🍀

この時はディスパッチに関しては試していなかったので、今回見てみようかなと思います。

今回はWildFly 35.0.0.1.FinalとApache Tomcat 10.1.0.36で確認します。

Jakarta Servletの非同期処理とディスパッチ

Jakarta Servletの仕様書で、非同期処理について書かれている箇所については前回まとめてみました。

Jakarta Servletの非同期処理をWildFly 35、Apache Tomcat 10.1で試す - CLOVER🍀

Jakarta Servlet Specification / The Servlet Interface / Servlet Life Cycle / Request Handling / Asynchronous processing

非同期処理を使っている時でも、AsyncContext#dispatchでディスパッチを行えることが書かれています。

When asynchronous processing begins on the request, another thread or callback may either generate the response and call complete or dispatch the request so that it may run in the context of the container using the AsyncContext.dispatch method.

また、asyncSupportedtrueServletからasyncSupportedfalseServletへもディスパッチできるようです。

Dispatching from a servlet that has asyncSupported=true to one where asyncSupported is set to false is allowed. In this case, the response will be committed when the service method of the servlet that does not support async is exited, and it is the container’s responsibility to call complete on the AsyncContext so that any interested AsyncListener instances will be notified. The AsyncListener.

ServletRequest#startAsyncを呼び出す時には、それまでにasyncSupportedfalseServletやフィルターがひとつでもあると
ダメだったんですけどね。ディスパッチ先ならOKのようです。

ディスパッチ先の同期Servletserviceメソッドが終了すると、レスポンスはコミットされることには注意が必要ですが。

同期Servletから非同期Servletへのディスパッチは不正ですが、IllegalStateExceptionをスローするかどうかは
ServletRequest#startAsyncを呼び出すまで遅延します。このため、非同期Servletでも明示的に非同期処理を開始しなければ
同期Servletとしても機能できることを意味します。

Dispatching from a synchronous servlet to an asynchronous servlet would be illegal. However the decision of throwing an IllegalStateException is deferred to the point when the application calls startAsync. This would allow a servlet to either function as a synchronous or an asynchronous servlet.

1回の非同期サイクル(ServletRequest#startAsyncの呼び出し)ごとに最大1回の非同期ディスパッチを実行できます。
同じ非同期サイクル内でさらにディスパッチを行おうとするとIllegalStateExceptionが発生します。

There can be at most one asynchronous dispatch operation per asynchronous cycle, which is started by a call to one of the ServletRequest.startAsync methods. Any attempt to perform additional asynchronous dispatch operations within the same asynchronous cycle is illegal and will result in an IllegalStateException. If startAsync is subsequently called on the dispatched request, then any of the dispatch methods may be called with the same restriction as above.

ディスパッチ後のリクエストでは、上記制限のもとでさらにディスパッチを行うことができます。

非同期処理下でのJSPの利用はデフォルトではサポートされていないようで、どのような動作になるかはコンテナ次第だと
されています。

Async processing in JSP would not be supported by default as it is used for content generation and async processing would have to be done before the content generation. It is up to the container how to handle this case. Once all the async activities are done, a dispatch to the JSP page using the AsyncContext.dispatch can be used for generating content.

ディスパッチを行うAsyncContext#dispatchには引数にパスを取るものと取らないものがあり、パスを指定する場合は
ServletContextからの相対パスになり/から指定します。パスを指定しない場合は、もともとのリクエストと 同じパス(HttpServletRequest#getRequestURI)に対してディスパッチされます。さらにServletContextを指定して
別のWebアプリケーションにディスパッチすることもできます。

AsyncContext (Jakarta Servlet API documentation)

今回は、ディスパッチと同期・非同期Servletの組み合わせを確認してみたいと思います。

環境

今回の環境はこちら。

$ java --version
openjdk 21.0.6 2025-01-21
OpenJDK Runtime Environment (build 21.0.6+7-Ubuntu-124.04.1)
OpenJDK 64-Bit Server VM (build 21.0.6+7-Ubuntu-124.04.1, mixed mode, sharing)


$ mvn --version
Apache Maven 3.9.9 (8e8579a9e76f7d015ee5ec7bfcdc97d260186937)
Maven home: $HOME/.sdkman/candidates/maven/current
Java version: 21.0.6, vendor: Ubuntu, runtime: /usr/lib/jvm/java-21-openjdk-amd64
Default locale: ja_JP, platform encoding: UTF-8
OS name: "linux", version: "6.8.0-54-generic", arch: "amd64", family: "unix"

WildFlyは35.0.0.1.Final、Apache Tomcatは10.1.0.36を使います。

準備

まずはMavenプロジェクトの準備から。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.littlewings</groupId>
    <artifactId>servlet-async-dispatch-example</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.release>21</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>jakarta.platform</groupId>
                <artifactId>jakarta.jakartaee-bom</artifactId>
                <version>10.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>jakarta.annotation</groupId>
            <artifactId>jakarta.annotation-api</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>2.0.16</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.16</version>
            <scope>runtime</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>ROOT</finalName>
    </build>

    <profiles>
        <profile>
            <id>wildfly</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.wildfly.plugins</groupId>
                        <artifactId>wildfly-maven-plugin</artifactId>
                        <version>5.1.2.Final</version>
                        <executions>
                            <execution>
                                <id>package</id>
                                <goals>
                                    <goal>package</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <overwrite-provisioned-server>true</overwrite-provisioned-server>
                            <discover-provisioning-info>
                                <version>35.0.1.Final</version>
                                <layers-for-jndi>
                                    <layer>ee-concurrency</layer>
                                </layers-for-jndi>
                            </discover-provisioning-info>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
        <profile>
            <id>tomcat</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.codehaus.cargo</groupId>
                        <artifactId>cargo-maven3-plugin</artifactId>
                        <version>1.10.17</version>
                        <configuration>
                            <container>
                                <containerId>tomcat10x</containerId>
                                <zipUrlInstaller>
                                    <url>https://archive.apache.org/dist/tomcat/tomcat-10/v10.1.36/bin/apache-tomcat-10.1.36.tar.gz</url>
                                </zipUrlInstaller>
                            </container>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>
</project>

SLF4JはWildFly上でもApache Tomcat上でもログ出力を行えるようにするために使います。

WildFlyWildFly Maven Pluginを使ってプロビジョニング、Apache TomcatCodehaus Cargo Maven 3 Pluginを使って
ダウンロードします。

WildFlyではJakarta Concurrecyを使うのですが明示的にManagedExecutorServiceは使わないので、レイヤーをlayers-for-jndi
引き込んでいます。

                        <configuration>
                            <overwrite-provisioned-server>true</overwrite-provisioned-server>
                            <discover-provisioning-info>
                                <version>35.0.1.Final</version>
                                <layers-for-jndi>
                                    <layer>ee-concurrency</layer>
                                </layers-for-jndi>
                            </discover-provisioning-info>
                        </configuration>

デフォルトはWildFlyで、Apache Tomcatを使う時は-P tomcatでプロファイルを切り替えます。

WildFlyは以下のコマンドでプロビジョニングと起動を行います。

$ mvn wildfly:run

Apache Tomcatは以下のコマンドでパッケージングと起動を行います。

$ mvn -P tomcat package cargo:run

Jakarta Servletで同期・非同期Servletとディスパッチの組み合わせを確認する

ここから先は、ServletJakarta Server Pages(以降JSP)、Filterを用意してディスパッチの組み合わせを確認していきます。

ざっくりと以下の組み合わせを試していきたいと思います。

  • 同期Servletを起点にして
    • 同期Servletへディスパッチ
    • JSPへディスパッチ
    • 非同期Servletへディスパッチ
  • 非同期Servletを起点にして
    • 同期Servletへディスパッチ
    • 非同期Servletへディスパッチ
    • JSPへディスパッチ

同期Servletのパスは/sync/〜で始め、非同期Servletのパスは/async/〜で始めることにします。

厳密には、もう少しネストした組み合わせにもします。

ベースの作成

まずは基本となる同期・非同期ServletJSP、Filterを作成します。それぞれWildFlyApache Tomcatで確認していきます。

起動コマンドは以下を使っている前提にして、以降では省略します。

## WildFly
$ mvn wildfly:run


## Apache Tomcat
$ mvn -P tomcat package cargo:run

同期Servlet

src/main/java/org/littlewings/servlet/async/SyncServlet.java

package org.littlewings.servlet.async;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebServlet("/sync/simple")
public class SyncServlet extends HttpServlet {
    private Logger logger = LoggerFactory.getLogger(SyncServlet.class);

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("do get");

        response.getWriter().println("Hello from Sync Servlet");
    }
}

JSP

src/main/webapp/WEB-INF/hello.jsp

Hello from JSP!!

JSPにディスパッチ(フォワードする)同期Servlet

src/main/java/org/littlewings/servlet/async/SyncViewJspServlet.java

package org.littlewings.servlet.async;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebServlet("/sync/jsp")
public class SyncViewJspServlet extends HttpServlet {
    private Logger logger = LoggerFactory.getLogger(SyncViewJspServlet.class);

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("do get");

        RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/hello.jsp");
        dispatcher.forward(request, response);
    }
}

同期Filter。

src/main/java/org/littlewings/servlet/async/SyncFilter.java

package org.littlewings.servlet.async;

import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebFilter(value = "/sync/*", dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD})
public class SyncFilter implements Filter {
    private Logger logger = LoggerFactory.getLogger(SyncFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.info("do filter / sync");

        chain.doFilter(request, response);
    }
}

同期Filterと非同期処理を組み合わせると動作しないのは前回確認しているので適用対象のパスを同期Servletに絞り、
ディスパッチの種類も非同期は含めていません。

非同期Servlet…にいく前に、非同期処理で使うスレッドプールを用意します。

Apache Tomcatを使うことも考えると、初期化やインジェクションなどができるように用意するのがするのが
めんどうだったので、ServletContextListenerを使ってServletContextにスレッドプールを登録することにしました。
このスレッドプールは複数のServletから使います。

src/main/java/org/littlewings/servlet/async/ExecutorInitializer.java

package org.littlewings.servlet.async;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@WebListener
public class ExecutorInitializer implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent event) {
        ExecutorService executorService;

        try {
            // Jakarta Concurrency(WildFly)
            executorService = InitialContext.doLookup("java:comp/DefaultManagedExecutorService");
        } catch (NamingException e) {
            // Tomcat
            executorService = Executors.newFixedThreadPool(10);
        }

        event.getServletContext().setAttribute("asyncWorker", executorService);
    }
}

では、非同期Servlet

src/main/java/org/littlewings/servlet/async/AsyncServlet.java

package org.littlewings.servlet.async;

import jakarta.servlet.AsyncContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.concurrent.ExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebServlet(value = "/async/simple", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    private Logger logger = LoggerFactory.getLogger(AsyncServlet.class);

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("do get");

        AsyncContext asyncContext = request.startAsync(request, response);

        ExecutorService executorService = (ExecutorService)request.getServletContext().getAttribute("asyncWorker");

        executorService.submit(() -> {
            logger.info("do task");

            try {
                HttpServletResponse res = (HttpServletResponse) asyncContext.getResponse();

                res.getWriter().println("Hello from Async Servlet");

                asyncContext.complete();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        });
    }
}

JSPは同期のものと同じものを使います。

JSPにディスパッチする非同期Servlet

src/main/java/org/littlewings/servlet/async/AsyncViewJspServlet.java

package org.littlewings.servlet.async;

import jakarta.servlet.AsyncContext;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.concurrent.ExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebServlet(value = "/async/jsp", asyncSupported = true)
public class AsyncViewJspServlet extends HttpServlet {
    private Logger logger = LoggerFactory.getLogger(AsyncViewJspServlet.class);

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("do get");

        AsyncContext asyncContext = request.startAsync();

        ExecutorService executorService = (ExecutorService)request.getServletContext().getAttribute("asyncWorker");

        executorService.submit(() -> {
            logger.info("do task");

            asyncContext.dispatch("/WEB-INF/hello.jsp");
        });
    }
}

AsyncContext#dispatchでディスパッチ先のパスを指定します。

            asyncContext.dispatch("/WEB-INF/hello.jsp");

非同期をサポートするFilter。

src/main/java/org/littlewings/servlet/async/AsyncSupportedFilter.java

package org.littlewings.servlet.async;

import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebFilter(value = "/*", asyncSupported = true, dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC})
public class AsyncSupportedFilter implements Filter {
    private Logger logger = LoggerFactory.getLogger(AsyncSupportedFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        logger.info("do filter / async supported");

        chain.doFilter(request, response);
    }
}

非同期をサポートするFilterは、すべてのパスに適用することにします。同期、非同期の両方で使えるはずなので。

DispatcherTypeASYNCを加えておきました。

このセットでまずは確認。

同期Servlet

## WildFly
$ curl localhost:8080/sync/simple
Hello from Sync Servlet


## Apache Tomcat
$ curl localhost:8080/sync/simple
Hello from Sync Servlet

ログ。

## WildFly
20:20:47,812 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:20:47,812 INFO  [org.littlewings.servlet.async.SyncFilter] (default task-1) do filter / sync
20:20:47,813 INFO  [org.littlewings.servlet.async.SyncServlet] (default task-1) do get


## Apache Tomcat
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.SyncServlet - do get

同期ServletJSP

## WildFly
$ curl localhost:8080/sync/jsp
Hello from JSP!!


## Apache Tomcat
$ curl localhost:8080/sync/jsp
Hello from JSP!!

ログ。

## WildFly
20:21:25,066 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:21:25,066 INFO  [org.littlewings.servlet.async.SyncFilter] (default task-1) do filter / sync
20:21:25,067 INFO  [org.littlewings.servlet.async.SyncViewJspServlet] (default task-1) do get
20:21:25,067 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported


## Apache Tomcat
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncViewJspServlet - do get
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported

非同期Servlet

## WildFly
$ curl localhost:8080/async/simple
Hello from Async Servlet


## Apache Tomcat
$ curl localhost:8080/async/simple
Hello from Async Servlet

ログ。

## WildFly
20:22:45,886 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:22:45,886 INFO  [org.littlewings.servlet.async.AsyncServlet] (default task-1) do get
20:22:45,888 INFO  [org.littlewings.servlet.async.AsyncServlet] (EE-ManagedExecutorService-default-Thread-3) do task


## Apache Tomcat
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.AsyncServlet - do get
[INFO] [pool-1-thread-1] INFO org.littlewings.servlet.async.AsyncServlet - do task

非同期ServletJSP

## WildFly
$ curl localhost:8080/async/jsp
Hello from JSP!!


## Apache Tomcat
$ curl localhost:8080/async/jsp
Hello from JSP!!

ログ。

## WildFly
20:23:40,577 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:23:40,578 INFO  [org.littlewings.servlet.async.AsyncViewJspServlet] (default task-1) do get
20:23:40,579 INFO  [org.littlewings.servlet.async.AsyncViewJspServlet] (EE-ManagedExecutorService-default-Thread-5) do task
20:23:40,582 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported

## Apache Tomcat
[INFO] [http-nio-8080-exec-7] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-7] INFO org.littlewings.servlet.async.AsyncViewJspServlet - do get
[INFO] [pool-1-thread-2] INFO org.littlewings.servlet.async.AsyncViewJspServlet - do task
[INFO] [http-nio-8080-exec-8] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported

特になにも設定していませんが、JSPは非同期Servletからディスパッチしても動くんですね。

ちなみに、Jakarta Server Pagesの仕様書には特にasyncについては書かれていませんでした。

Jakarta Server Pages

またログをよく見ると気づきますが、JSPにディスパッチ後のフィルターはHTTPリクエストを処理するスレッドで
動いています。

Servletの前にディスパッチするServletを置く

次は、これらのServletの前にパスに応じてディスパッチするServletを用意してみます。

同期Servlet、非同期Servletにディスパッチする同期Servlet

src/main/java/org/littlewings/servlet/async/SyncDispatchServlet.java

package org.littlewings.servlet.async;

import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebServlet("/sync/dispatch/*")
public class SyncDispatchServlet extends HttpServlet {
    private Logger logger = LoggerFactory.getLogger(SyncDispatchServlet.class);

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String nextPath =
                switch (request.getPathInfo()) {
                    case "/simple" -> "/sync/simple";
                    case "/jsp" -> "/sync/jsp";
                    case "/async/simple" -> "/async/simple";
                    case "/async/jsp" -> "/async/jsp";
                    default -> throw new IllegalArgumentException("not found");
                };

        logger.info("dispatch from access path = {}{}, next -> {}", request.getServletPath(), request.getPathInfo(), nextPath);

        RequestDispatcher dispatcher = request.getRequestDispatcher(nextPath);
        dispatcher.forward(request, response);
    }
}

/async付きのパスだと、非同期Servletにディスパッチするようにしています。ここで使うのはRequestDispatcherです。

同期Servlet、非同期Servletにディスパッチする非同期Servlet

src/main/java/org/littlewings/servlet/async/AsyncDispatchServlet.java

package org.littlewings.servlet.async;

import jakarta.servlet.AsyncContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebServlet(value = "/async/dispatch/*", asyncSupported = true)
public class AsyncDispatchServlet extends HttpServlet {
    private Logger logger = LoggerFactory.getLogger(AsyncDispatchServlet.class);

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("do get");

        AsyncContext asyncContext = request.startAsync();

        ExecutorService executorService = (ExecutorService) request.getServletContext().getAttribute("asyncWorker");

        executorService.submit(() -> {
            HttpServletRequest req = (HttpServletRequest) asyncContext.getRequest();

            String nextPath =
                    switch (req.getPathInfo()) {
                        case "/sync/simple" -> "/sync/simple";
                        case "/sync/jsp" -> "/sync/jsp";
                        case "/simple" -> "/async/simple";
                        case "/jsp" -> "/async/jsp";
                        default -> throw new IllegalArgumentException("not found");
                    };

            logger.info("dispatch from access path = {}{}, next -> {}", req.getServletPath(), req.getPathInfo(), nextPath);

            asyncContext.dispatch(nextPath);
        });
    }
}

こちらは、/sync付きのパスだと同期Servletにディスパッチします。ここで使うのはAsyncContext#dispatchです。

確認してみましょう。

同期Servetからのディスパッチ。

## WildFly
### 同期Serlvetへ
$ curl -i localhost:8080/sync/dispatch/simple
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 25
Date: Sun, 02 Mar 2025 11:38:24 GMT

Hello from Sync Servlet


### 同期Serlvet+JSPへ
$ curl -i localhost:8080/sync/dispatch/jsp
HTTP/1.1 200 OK
Connection: keep-alive
X-Powered-By: JSP/3.1
Set-Cookie: JSESSIONID=Dmt0yczxveGVZMkr3imJC7nOSw0GuBa3kh0iiSuS.ikaruga; path=/
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 17
Date: Sun, 02 Mar 2025 11:39:24 GMT

Hello from JSP!!


### 非同期Serlvetへ
$ curl -i localhost:8080/sync/dispatch/async/simple
HTTP/1.1 500 Internal Server Error
Connection: keep-alive
Content-Type: text/html;charset=UTF-8
Content-Length: 15494
Date: Sun, 02 Mar 2025 11:39:51 GMT

<html><head><title>ERROR</title><style>
body {

〜省略〜


### 非同期Serlvet+JSPへ
$ curl -i localhost:8080/sync/dispatch/async/jsp
HTTP/1.1 500 Internal Server Error
Connection: keep-alive
Content-Type: text/html;charset=UTF-8
Content-Length: 15505
Date: Sun, 02 Mar 2025 11:41:03 GMT

<html><head><title>ERROR</title><style>
body {


## Apache Tomcat
### 同期Serlvetへ
$ curl -i localhost:8080/sync/dispatch/simple
HTTP/1.1 200
Content-Length: 24
Date: Sun, 02 Mar 2025 11:42:20 GMT

Hello from Sync Servlet


### 同期Serlvet+JSPへ
$ curl -i localhost:8080/sync/dispatch/jsp
HTTP/1.1 200
Set-Cookie: JSESSIONID=C880BF89D731A130F9182FAA6D65632A; Path=/; HttpOnly
Content-Type: text/html;charset=UTF-8
Content-Length: 17
Date: Sun, 02 Mar 2025 11:42:49 GMT

Hello from JSP!!


### 非同期Serlvetへ
$ curl -i localhost:8080/sync/dispatch/async/simple
HTTP/1.1 500
Content-Type: text/html;charset=utf-8
Content-Language: ja
Content-Length: 2198
Date: Sun, 02 Mar 2025 11:43:20 GMT
Connection: close

<!doctype html><html lang="ja"><head><title>HTTPステータス 500 – Internal Server Error</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTPステータス 500 – Internal Server Error</h1><hr class="line" /><p><b>タイプ</b> 例外報告</p><p><b>メッセージ</b> 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。</p><p><b>説明</b> サーバーは予期しない条件に遭遇しました。それはリクエストの実行を妨げます。</p><p><b>例 外</b></p><pre>java.lang.IllegalStateException: 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。

〜省略〜


### 非同期Serlvet+JSPへ
$ curl -i localhost:8080/sync/dispatch/async/jsp
HTTP/1.1 500
Content-Type: text/html;charset=utf-8
Content-Language: ja
Content-Length: 2281
Date: Sun, 02 Mar 2025 11:44:30 GMT
Connection: close

<!doctype html><html lang="ja"><head><title>HTTPステータス 500 – Internal Server Error</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTPステータス 500 – Internal Server Error</h1><hr class="line" /><p><b>タイプ</b> 例外報告</p><p><b>メッセージ</b> 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。</p><p><b>説明</b> サーバーは予期しない条件に遭遇しました。それはリクエストの実行を妨げます。</p><p><b>例 外</b></p><pre>java.lang.IllegalStateException: 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。

〜省略〜

というわけで、同期Servletから非同期Servletへのディスパッチはしっかりエラーになりました。

ログを見てみましょう。

## WildFly
### 同期Serlvetへ
20:38:24,887 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:38:24,887 INFO  [org.littlewings.servlet.async.SyncFilter] (default task-1) do filter / sync
20:38:24,888 INFO  [org.littlewings.servlet.async.SyncDispatchServlet] (default task-1) dispatch from access path = /sync/dispatch/simple, next -> /sync/simple
20:38:24,890 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:38:24,890 INFO  [org.littlewings.servlet.async.SyncFilter] (default task-1) do filter / sync
20:38:24,890 INFO  [org.littlewings.servlet.async.SyncServlet] (default task-1) do get


### 同期Serlvet+JSPへ
20:39:24,104 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:39:24,104 INFO  [org.littlewings.servlet.async.SyncFilter] (default task-1) do filter / sync
20:39:24,105 INFO  [org.littlewings.servlet.async.SyncDispatchServlet] (default task-1) dispatch from access path = /sync/dispatch/jsp, next -> /sync/jsp
20:39:24,105 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:39:24,106 INFO  [org.littlewings.servlet.async.SyncFilter] (default task-1) do filter / sync
20:39:24,106 INFO  [org.littlewings.servlet.async.SyncViewJspServlet] (default task-1) do get
20:39:24,116 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported


### 非同期Serlvetへ
20:39:51,503 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:39:51,503 INFO  [org.littlewings.servlet.async.SyncFilter] (default task-1) do filter / sync
20:39:51,503 INFO  [org.littlewings.servlet.async.SyncDispatchServlet] (default task-1) dispatch from access path = /sync/dispatch/async/simple, next -> /async/simple
20:39:51,504 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:39:51,504 INFO  [org.littlewings.servlet.async.AsyncServlet] (default task-1) do get
20:39:51,507 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /async/simple: java.lang.RuntimeException: java.lang.IllegalStateException: UT010026: Async is not supported for this request, as not all filters or Servlets were marked as supporting async
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:211)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.RequestDispatcherImpl.forwardImplSetup(RequestDispatcherImpl.java:137)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:100)
        at deployment.ROOT.war//org.littlewings.servlet.async.SyncDispatchServlet.doGet(SyncDispatchServlet.java:31)
        at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527)
        at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
        at deployment.ROOT.war//org.littlewings.servlet.async.SyncFilter.doFilter(SyncFilter.java:22)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
        at deployment.ROOT.war//org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
        at org.wildfly.security.elytron-web.undertow-server@4.1.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
        at org.wildfly.security.elytron-web.undertow-server@4.1.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.core@2.3.18.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
        at io.undertow.core@2.3.18.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
        at org.wildfly.security.elytron-web.undertow-server-servlet@4.1.0.Final//org.wildfly.elytron.web.undertow.server.servlet.CleanUpHandler.handleRequest(CleanUpHandler.java:38)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at org.wildfly.extension.undertow@35.0.1.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:44)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at org.wildfly.extension.undertow@35.0.1.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:51)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:276)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:132)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
        at org.wildfly.extension.undertow@35.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1421)
        at org.wildfly.extension.undertow@35.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1421)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:256)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:101)
        at io.undertow.core@2.3.18.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:395)
        at io.undertow.core@2.3.18.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:861)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
        at org.jboss.xnio@3.8.16.Final//org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)
        at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.IllegalStateException: UT010026: Async is not supported for this request, as not all filters or Servlets were marked as supporting async
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.HttpServletRequestImpl.startAsync(HttpServletRequestImpl.java:1096)
        at deployment.ROOT.war//org.littlewings.servlet.async.AsyncServlet.doGet(AsyncServlet.java:23)
        at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527)
        at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
        at deployment.ROOT.war//org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
        at org.wildfly.security.elytron-web.undertow-server@4.1.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
        at org.wildfly.security.elytron-web.undertow-server@4.1.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:258)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchToPath(ServletInitialHandler.java:183)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:189)
        ... 53 more


### 非同期Serlvet+JSPへ
20:41:03,057 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:41:03,058 INFO  [org.littlewings.servlet.async.SyncFilter] (default task-1) do filter / sync
20:41:03,058 INFO  [org.littlewings.servlet.async.SyncDispatchServlet] (default task-1) dispatch from access path = /sync/dispatch/async/jsp, next -> /async/jsp
20:41:03,059 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:41:03,060 INFO  [org.littlewings.servlet.async.AsyncViewJspServlet] (default task-1) do get
20:41:03,060 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /async/jsp: java.lang.RuntimeException: java.lang.IllegalStateException: UT010026: Async is not supported for this request, as not all filters or Servlets were marked as supporting async
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:211)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.RequestDispatcherImpl.forwardImplSetup(RequestDispatcherImpl.java:137)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:100)
        at deployment.ROOT.war//org.littlewings.servlet.async.SyncDispatchServlet.doGet(SyncDispatchServlet.java:31)
        at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527)
        at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
        at deployment.ROOT.war//org.littlewings.servlet.async.SyncFilter.doFilter(SyncFilter.java:22)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
        at deployment.ROOT.war//org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
        at org.wildfly.security.elytron-web.undertow-server@4.1.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
        at org.wildfly.security.elytron-web.undertow-server@4.1.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.SSLInformationAssociationHandler.handleRequest(SSLInformationAssociationHandler.java:117)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.ServletAuthenticationCallHandler.handleRequest(ServletAuthenticationCallHandler.java:57)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.core@2.3.18.Final//io.undertow.security.handlers.AbstractConfidentialityHandler.handleRequest(AbstractConfidentialityHandler.java:46)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.ServletConfidentialityConstraintHandler.handleRequest(ServletConfidentialityConstraintHandler.java:64)
        at io.undertow.core@2.3.18.Final//io.undertow.security.handlers.AbstractSecurityContextAssociationHandler.handleRequest(AbstractSecurityContextAssociationHandler.java:43)
        at org.wildfly.security.elytron-web.undertow-server-servlet@4.1.0.Final//org.wildfly.elytron.web.undertow.server.servlet.CleanUpHandler.handleRequest(CleanUpHandler.java:38)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at org.wildfly.extension.undertow@35.0.1.Final//org.wildfly.extension.undertow.security.jacc.JACCContextIdHandler.handleRequest(JACCContextIdHandler.java:44)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at org.wildfly.extension.undertow@35.0.1.Final//org.wildfly.extension.undertow.deployment.GlobalRequestControllerHandler.handleRequest(GlobalRequestControllerHandler.java:51)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.SendErrorPageHandler.handleRequest(SendErrorPageHandler.java:52)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler.handleFirstRequest(ServletInitialHandler.java:276)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:135)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler$2.call(ServletInitialHandler.java:132)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ServletRequestContextThreadSetupAction$1.call(ServletRequestContextThreadSetupAction.java:48)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ContextClassLoaderSetupAction$1.call(ContextClassLoaderSetupAction.java:43)
        at org.wildfly.extension.undertow@35.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1421)
        at org.wildfly.extension.undertow@35.0.1.Final//org.wildfly.extension.undertow.deployment.UndertowDeploymentInfoService$UndertowThreadSetupAction.lambda$create$0(UndertowDeploymentInfoService.java:1421)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:256)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler$1.handleRequest(ServletInitialHandler.java:101)
        at io.undertow.core@2.3.18.Final//io.undertow.server.Connectors.executeRootHandler(Connectors.java:395)
        at io.undertow.core@2.3.18.Final//io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:861)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:1990)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1486)
        at org.jboss.threads@2.4.0.Final//org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1377)
        at org.jboss.xnio@3.8.16.Final//org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)
        at java.base/java.lang.Thread.run(Thread.java:1583)
Caused by: java.lang.IllegalStateException: UT010026: Async is not supported for this request, as not all filters or Servlets were marked as supporting async
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.HttpServletRequestImpl.startAsync(HttpServletRequestImpl.java:1070)
        at deployment.ROOT.war//org.littlewings.servlet.async.AsyncViewJspServlet.doGet(AsyncViewJspServlet.java:24)
        at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:527)
        at jakarta.servlet.api@6.0.0//jakarta.servlet.http.HttpServlet.service(HttpServlet.java:614)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:129)
        at deployment.ROOT.war//org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.core.ManagedFilter.doFilter(ManagedFilter.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler$FilterChainImpl.doFilter(FilterHandler.java:131)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.FilterHandler.handleRequest(FilterHandler.java:84)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.security.ServletSecurityRoleHandler.handleRequest(ServletSecurityRoleHandler.java:62)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletChain$1.handleRequest(ServletChain.java:68)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletDispatchingHandler.handleRequest(ServletDispatchingHandler.java:36)
        at org.wildfly.security.elytron-web.undertow-server@4.1.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.lambda$handleRequest$1(ElytronRunAsHandler.java:68)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.FlexibleIdentityAssociation.runAsFunctionEx(FlexibleIdentityAssociation.java:103)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAsFunctionEx(Scoped.java:161)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:73)
        at org.wildfly.security.elytron-web.undertow-server@4.1.0.Final//org.wildfly.elytron.web.undertow.server.ElytronRunAsHandler.handleRequest(ElytronRunAsHandler.java:67)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.RedirectDirHandler.handleRequest(RedirectDirHandler.java:68)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.core@2.3.18.Final//io.undertow.server.handlers.PredicateHandler.handleRequest(PredicateHandler.java:43)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchRequest(ServletInitialHandler.java:258)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.handlers.ServletInitialHandler.dispatchToPath(ServletInitialHandler.java:183)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.RequestDispatcherImpl.forwardImpl(RequestDispatcherImpl.java:189)
        ... 53 more




## Apache Tomcat
### 同期Serlvetへ
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.SyncDispatchServlet - dispatch from access path = /sync/dispatch/simple, next -> /sync/simple
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.SyncServlet - do get


### 同期Serlvet+JSPへ
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncDispatchServlet - dispatch from access path = /sync/dispatch/jsp, next -> /sync/jsp
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncViewJspServlet - do get
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported


### 非同期Serlvetへ
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncDispatchServlet - dispatch from access path = /sync/dispatch/jsp, next -> /sync/jsp
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncViewJspServlet - do get
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported


[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.SyncDispatchServlet - dispatch from access path = /sync/dispatch/async/simple, next -> /async/simple
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.AsyncServlet - do get
[INFO] 3月 02, 2025 8:43:20 午後 org.apache.catalina.connector.Request startAsync
[INFO] 警告: 処理チェーン内の次のクラスが非同期をサポートしていないため、非同期を開始できません [org.littlewings.servlet.async.SyncDispatchServlet,org.littlewings.servlet.async.SyncFilter]
[INFO] java.lang.IllegalStateException: 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。
[INFO]  at org.apache.catalina.connector.Request.startAsync(Request.java:1510)
[INFO]  at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:720)
[INFO]  at jakarta.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:358)
[INFO]  at org.littlewings.servlet.async.AsyncServlet.doGet(AsyncServlet.java:23)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:633)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:409)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:331)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:268)
[INFO]  at org.littlewings.servlet.async.SyncDispatchServlet.doGet(SyncDispatchServlet.java:31)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.SyncFilter.doFilter(SyncFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
[INFO]  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
[INFO]  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
[INFO]  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
[INFO]  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
[INFO]  at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:663)
[INFO]  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
[INFO]  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
[INFO]  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
[INFO]  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
[INFO]  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
[INFO]  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
[INFO]  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
[INFO]  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO]
[INFO] 3月 02, 2025 8:43:20 午後 org.apache.catalina.core.ApplicationDispatcher invoke
[INFO] 重大: サーブレット [org.littlewings.servlet.async.AsyncServlet] のServlet.service()が例外を投げました
[INFO] java.lang.IllegalStateException: 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。
[INFO]  at org.apache.catalina.connector.Request.startAsync(Request.java:1510)
[INFO]  at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:720)
[INFO]  at jakarta.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:358)
[INFO]  at org.littlewings.servlet.async.AsyncServlet.doGet(AsyncServlet.java:23)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:633)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:409)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:331)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:268)
[INFO]  at org.littlewings.servlet.async.SyncDispatchServlet.doGet(SyncDispatchServlet.java:31)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.SyncFilter.doFilter(SyncFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
[INFO]  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
[INFO]  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
[INFO]  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
[INFO]  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
[INFO]  at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:663)
[INFO]  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
[INFO]  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
[INFO]  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
[INFO]  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
[INFO]  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
[INFO]  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
[INFO]  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
[INFO]  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO]
[INFO] 3月 02, 2025 8:43:20 午後 org.apache.catalina.core.StandardWrapperValve invoke
[INFO] 重大: サーブレット [org.littlewings.servlet.async.SyncDispatchServlet] のServlet.service()が例外を投げました
[INFO] java.lang.IllegalStateException: 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。
[INFO]  at org.apache.catalina.connector.Request.startAsync(Request.java:1510)
[INFO]  at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:720)
[INFO]  at jakarta.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:358)
[INFO]  at org.littlewings.servlet.async.AsyncServlet.doGet(AsyncServlet.java:23)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:633)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:409)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:331)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:268)
[INFO]  at org.littlewings.servlet.async.SyncDispatchServlet.doGet(SyncDispatchServlet.java:31)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.SyncFilter.doFilter(SyncFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
[INFO]  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
[INFO]  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
[INFO]  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
[INFO]  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
[INFO]  at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:663)
[INFO]  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
[INFO]  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
[INFO]  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
[INFO]  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
[INFO]  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
[INFO]  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
[INFO]  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
[INFO]  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO]


### 非同期Serlvet+JSPへ
[INFO] [http-nio-8080-exec-6] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-6] INFO org.littlewings.servlet.async.SyncFilter - do filter / sync
[INFO] [http-nio-8080-exec-6] INFO org.littlewings.servlet.async.SyncDispatchServlet - dispatch from access path = /sync/dispatch/async/jsp, next -> /async/jsp
[INFO] [http-nio-8080-exec-6] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-6] INFO org.littlewings.servlet.async.AsyncViewJspServlet - do get
[INFO] 3月 02, 2025 8:44:30 午後 org.apache.catalina.connector.Request startAsync
[INFO] 警告: 処理チェーン内の次のクラスが非同期をサポートしていないため、非同期を開始できません [org.littlewings.servlet.async.SyncDispatchServlet,org.littlewings.servlet.async.SyncFilter]
[INFO] java.lang.IllegalStateException: 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。
[INFO]  at org.apache.catalina.connector.Request.startAsync(Request.java:1510)
[INFO]  at org.apache.catalina.connector.Request.startAsync(Request.java:1504)
[INFO]  at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:713)
[INFO]  at jakarta.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:341)
[INFO]  at org.littlewings.servlet.async.AsyncViewJspServlet.doGet(AsyncViewJspServlet.java:24)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:633)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:409)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:331)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:268)
[INFO]  at org.littlewings.servlet.async.SyncDispatchServlet.doGet(SyncDispatchServlet.java:31)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.SyncFilter.doFilter(SyncFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
[INFO]  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
[INFO]  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
[INFO]  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
[INFO]  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
[INFO]  at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:663)
[INFO]  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
[INFO]  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
[INFO]  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
[INFO]  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
[INFO]  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
[INFO]  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
[INFO]  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
[INFO]  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO]
[INFO] 3月 02, 2025 8:44:30 午後 org.apache.catalina.core.ApplicationDispatcher invoke
[INFO] 重大: サーブレット [org.littlewings.servlet.async.AsyncViewJspServlet] のServlet.service()が例外を投げました
[INFO] java.lang.IllegalStateException: 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。
[INFO]  at org.apache.catalina.connector.Request.startAsync(Request.java:1510)
[INFO]  at org.apache.catalina.connector.Request.startAsync(Request.java:1504)
[INFO]  at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:713)
[INFO]  at jakarta.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:341)
[INFO]  at org.littlewings.servlet.async.AsyncViewJspServlet.doGet(AsyncViewJspServlet.java:24)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:633)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:409)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:331)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:268)
[INFO]  at org.littlewings.servlet.async.SyncDispatchServlet.doGet(SyncDispatchServlet.java:31)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.SyncFilter.doFilter(SyncFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
[INFO]  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
[INFO]  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
[INFO]  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
[INFO]  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
[INFO]  at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:663)
[INFO]  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
[INFO]  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
[INFO]  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
[INFO]  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
[INFO]  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
[INFO]  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
[INFO]  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
[INFO]  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO]
[INFO] 3月 02, 2025 8:44:30 午後 org.apache.catalina.core.StandardWrapperValve invoke
[INFO] 重大: サーブレット [org.littlewings.servlet.async.SyncDispatchServlet] のServlet.service()が例外を投げました
[INFO] java.lang.IllegalStateException: 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。
[INFO]  at org.apache.catalina.connector.Request.startAsync(Request.java:1510)
[INFO]  at org.apache.catalina.connector.Request.startAsync(Request.java:1504)
[INFO]  at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:713)
[INFO]  at jakarta.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:341)
[INFO]  at org.littlewings.servlet.async.AsyncViewJspServlet.doGet(AsyncViewJspServlet.java:24)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:633)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:409)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:331)
[INFO]  at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:268)
[INFO]  at org.littlewings.servlet.async.SyncDispatchServlet.doGet(SyncDispatchServlet.java:31)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
[INFO]  at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.SyncFilter.doFilter(SyncFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.littlewings.servlet.async.AsyncSupportedFilter.doFilter(AsyncSupportedFilter.java:22)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
[INFO]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
[INFO]  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
[INFO]  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
[INFO]  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
[INFO]  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
[INFO]  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
[INFO]  at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:663)
[INFO]  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
[INFO]  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
[INFO]  at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
[INFO]  at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
[INFO]  at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
[INFO]  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1743)
[INFO]  at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
[INFO]  at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
[INFO]  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO]

WildFlyApache Tomcatのいずれも、同期Servletから非同期Servletにディスパッチ後、ServletRequest#startAsync
呼び出した時点でIllegalStateExceptionがスローされています。

## WildFly
Caused by: java.lang.IllegalStateException: UT010026: Async is not supported for this request, as not all filters or Servlets were marked as supporting async


## Apache Tomcat
[INFO] 重大: サーブレット [org.littlewings.servlet.async.SyncDispatchServlet] のServlet.service()が例外を投げました
[INFO] java.lang.IllegalStateException: 現在のチェーンのフィルタまたはサーブレットは非同期操作をサポートしていません。

非同期Servetからのディスパッチ。

## WildFly
### 同期Serlvetへ
$ curl -i localhost:8080/async/dispatch/sync/simple
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 25
Date: Sun, 02 Mar 2025 11:49:06 GMT

Hello from Sync Servlet


### 同期Serlvet+JSPへ
$ curl -i localhost:8080/async/dispatch/sync/jsp
HTTP/1.1 200 OK
Connection: keep-alive
X-Powered-By: JSP/3.1
Set-Cookie: JSESSIONID=xt7wcq1k-cduTXd0VyYlMKHXUTndIhI929oc_6yv.ikaruga; path=/
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 17
Date: Sun, 02 Mar 2025 11:49:31 GMT

Hello from JSP!!


### 非同期Serlvetへ
$ curl -i localhost:8080/async/dispatch/simple
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 26
Date: Sun, 02 Mar 2025 11:49:57 GMT

Hello from Async Servlet


### 非同期Serlvet+JSPへ
$ curl -i localhost:8080/async/dispatch/jsp
HTTP/1.1 200 OK
Connection: keep-alive
X-Powered-By: JSP/3.1
Set-Cookie: JSESSIONID=Shm7SiE5rEcXgbT7Qgij7g_Pqcl1ZJPlRUGKOVi3.ikaruga; path=/
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 17
Date: Sun, 02 Mar 2025 11:50:25 GMT

Hello from JSP!!


## Apache Tomcat
### 同期Serlvetへ
$ curl -i localhost:8080/async/dispatch/sync/simple
HTTP/1.1 200
Content-Length: 24
Date: Sun, 02 Mar 2025 11:52:59 GMT

Hello from Sync Servlet


### 同期Serlvet+JSPへ
$ curl -i localhost:8080/async/dispatch/sync/jsp
HTTP/1.1 200
Set-Cookie: JSESSIONID=B0A56A254F1942A7E22C9274B3E9C040; Path=/; HttpOnly
Content-Type: text/html;charset=UTF-8
Content-Length: 17
Date: Sun, 02 Mar 2025 11:53:30 GMT

Hello from JSP!!


### 非同期Serlvetへ
$ curl -i localhost:8080/async/dispatch/simple
HTTP/1.1 200
Content-Length: 25
Date: Sun, 02 Mar 2025 11:53:55 GMT

Hello from Async Servlet


### 非同期Serlvet+JSPへ
$ curl -i localhost:8080/async/dispatch/jsp
HTTP/1.1 200
Set-Cookie: JSESSIONID=AA6B76172CB8CE225BFDB6371860C81A; Path=/; HttpOnly
Content-Type: text/html;charset=UTF-8
Content-Length: 17
Date: Sun, 02 Mar 2025 11:54:20 GMT

Hello from JSP!!

ログ。

## WildFly
### 同期Serlvetへ
20:49:06,612 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:49:06,612 INFO  [org.littlewings.servlet.async.AsyncDispatchServlet] (default task-1) do get
20:49:06,617 INFO  [org.littlewings.servlet.async.AsyncDispatchServlet] (EE-ManagedExecutorService-default-Thread-1) dispatch from access path = /async/dispatch/sync/simple, next -> /sync/simple
20:49:06,619 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:49:06,620 INFO  [org.littlewings.servlet.async.SyncServlet] (default task-1) do get


### 同期Serlvet+JSPへ
20:49:31,487 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:49:31,487 INFO  [org.littlewings.servlet.async.AsyncDispatchServlet] (default task-1) do get
20:49:31,488 INFO  [org.littlewings.servlet.async.AsyncDispatchServlet] (EE-ManagedExecutorService-default-Thread-2) dispatch from access path = /async/dispatch/sync/jsp, next -> /sync/jsp
20:49:31,490 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:49:31,490 INFO  [org.littlewings.servlet.async.SyncViewJspServlet] (default task-1) do get
20:49:31,501 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported


### 非同期Serlvetへ
20:49:57,957 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:49:57,958 INFO  [org.littlewings.servlet.async.AsyncDispatchServlet] (default task-1) do get
20:49:57,959 INFO  [org.littlewings.servlet.async.AsyncDispatchServlet] (EE-ManagedExecutorService-default-Thread-3) dispatch from access path = /async/dispatch/simple, next -> /async/simple
20:49:57,960 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:49:57,960 INFO  [org.littlewings.servlet.async.AsyncServlet] (default task-1) do get
20:49:57,961 INFO  [org.littlewings.servlet.async.AsyncServlet] (EE-ManagedExecutorService-default-Thread-4) do task


### 非同期Serlvet+JSPへ
20:50:25,409 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:50:25,410 INFO  [org.littlewings.servlet.async.AsyncDispatchServlet] (default task-1) do get
20:50:25,410 INFO  [org.littlewings.servlet.async.AsyncDispatchServlet] (EE-ManagedExecutorService-default-Thread-5) dispatch from access path = /async/dispatch/jsp, next -> /async/jsp
20:50:25,412 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
20:50:25,412 INFO  [org.littlewings.servlet.async.AsyncViewJspServlet] (default task-1) do get
20:50:25,414 INFO  [org.littlewings.servlet.async.AsyncViewJspServlet] (EE-ManagedExecutorService-default-Thread-6) do task
20:50:25,415 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported



## Apache Tomcat
### 同期Serlvetへ
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.AsyncDispatchServlet - do get
[INFO] [pool-1-thread-1] INFO org.littlewings.servlet.async.AsyncDispatchServlet - dispatch from access path = /async/dispatch/sync/simple, next -> /sync/simple
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.SyncServlet - do get


### 同期Serlvet+JSPへ
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.AsyncDispatchServlet - do get
[INFO] [pool-1-thread-2] INFO org.littlewings.servlet.async.AsyncDispatchServlet - dispatch from access path = /async/dispatch/sync/jsp, next -> /sync/jsp
[INFO] [http-nio-8080-exec-6] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-6] INFO org.littlewings.servlet.async.SyncViewJspServlet - do get
[INFO] [http-nio-8080-exec-6] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported


### 非同期Serlvetへ
[INFO] [http-nio-8080-exec-7] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-7] INFO org.littlewings.servlet.async.AsyncDispatchServlet - do get
[INFO] [pool-1-thread-3] INFO org.littlewings.servlet.async.AsyncDispatchServlet - dispatch from access path = /async/dispatch/simple, next -> /async/simple
[INFO] [http-nio-8080-exec-8] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-8] INFO org.littlewings.servlet.async.AsyncServlet - do get
[INFO] [pool-1-thread-4] INFO org.littlewings.servlet.async.AsyncServlet - do task


### 非同期Serlvet+JSPへ
[INFO] [http-nio-8080-exec-10] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-10] INFO org.littlewings.servlet.async.AsyncDispatchServlet - do get
[INFO] [pool-1-thread-5] INFO org.littlewings.servlet.async.AsyncDispatchServlet - dispatch from access path = /async/dispatch/jsp, next -> /async/jsp
[INFO] [http-nio-8080-exec-1] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-1] INFO org.littlewings.servlet.async.AsyncViewJspServlet - do get
[INFO] [pool-1-thread-6] INFO org.littlewings.servlet.async.AsyncViewJspServlet - do task
[INFO] [http-nio-8080-exec-2] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported

非同期Servletからは、同期・非同期Servletのどちらにディスパッチしても問題なく動作します。

非同期Servletからディスパッチしても、転送先のServletはHTTPアクセスを処理するスレッドで動作していることがここでも
確認できます。

2回ディスパッチしてみる

ここまでで、ディスパッチ自体は複数繰り返してもOKでしたが、最大1回というのはServletRequest#startAsync
呼び出した非同期サイクルで1回のみ可能ということを一応確認しておきます。

こんな非同期Servletを用意。

src/main/java/org/littlewings/servlet/async/AsyncBadDispatchServlet.java

package org.littlewings.servlet.async;

import jakarta.servlet.AsyncContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@WebServlet(value = "/async/bad/*", asyncSupported = true)
public class AsyncBadDispatchServlet extends HttpServlet {
    private Logger logger = LoggerFactory.getLogger(AsyncBadDispatchServlet.class);

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        logger.info("do get");

        AsyncContext asyncContext = request.startAsync(request, response);

        ExecutorService executorService = (ExecutorService) request.getServletContext().getAttribute("asyncWorker");

        executorService.submit(() -> {
            logger.info("do task");

            if ("jsp".equals(((HttpServletRequest) asyncContext.getRequest()).getQueryString())) {
                logger.info("dispatch jsp");
                asyncContext.dispatch("/jsp");

                try {
                    asyncContext.dispatch("/simple");
                } catch (IllegalStateException e) {
                    logger.info("error = {}", e.getMessage(), e);
                }
            } else {
                logger.info("do dispatch simple");
                asyncContext.dispatch("/simple");

                try {
                    asyncContext.dispatch("/simple");
                } catch (IllegalStateException e) {
                    logger.info("error = {}", e.getMessage(), e);
                }
            }
        });
    }
}

それぞれ2回AsyncContext#dispatchを呼び出しています。ディスパッチ先は非同期Servletおよび非同期ServletJSPですね。

## WildFly
### 非同期Servletへ
$ curl -i localhost:8080/async/bad/simple
HTTP/1.1 404 Not Found
Connection: keep-alive
Content-Type: text/html;charset=UTF-8
Content-Length: 68
Date: Sun, 02 Mar 2025 12:03:15 GMT

<html><head><title>Error</title></head><body>Not Found</body></html>


### 非同期Servlet+JSPへ
$ curl -i localhost:8080/async/bad/jsp
HTTP/1.1 404 Not Found
Connection: keep-alive
Content-Type: text/html;charset=UTF-8
Content-Length: 68
Date: Sun, 02 Mar 2025 12:04:05 GMT

<html><head><title>Error</title></head><body>Not Found</body></html>


## Apache Tomcat
### 非同期Servletへ
$ curl -i localhost:8080/async/bad/simple
HTTP/1.1 404
Content-Type: text/html;charset=utf-8
Content-Language: ja
Content-Length: 902
Date: Sun, 02 Mar 2025 12:05:16 GMT

<!doctype html><html lang="ja"><head><title>HTTPステータス 404 – 見つかりません</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTPステータス 404 – 見つかりません</h1><hr class="line" /><p><b>タイプ</b> ステータスレポート</p><p><b>メッセージ</b> 要求されたリソース [&#47;simple] は利用できません。</p><p><b>説明</b> オリジンサーバーは、ターゲットリソースの現在の表現を見つけられなかったか、またはそれが存在することを開示するつもりはありません。</p><hr class="line" /><h3>Apache Tomcat/10.1.36</h3></body></html>


### 非同期Servlet+JSPへ
$ curl -i localhost:8080/async/bad/jsp
HTTP/1.1 404
Content-Type: text/html;charset=utf-8
Content-Language: ja
Content-Length: 902
Date: Sun, 02 Mar 2025 12:05:49 GMT

<!doctype html><html lang="ja"><head><title>HTTPステータス 404 – 見つかりません</title><style type="text/css">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTPステータス 404 – 見つかりません</h1><hr class="line" /><p><b>タイプ</b> ステータスレポート</p><p><b>メッセージ</b> 要求されたリソース [&#47;simple] は利用できません。</p><p><b>説明</b> オリジンサーバーは、ターゲットリソースの現在の表現を見つけられなかったか、またはそれが存在することを開示するつもりはありません。</p><hr class="line" /><h3>Apache Tomcat/10.1.36</h3></body></html>

今回のコードの場合は、404になりました。

ログ。

## WildFly
### 非同期Servletへ
21:03:15,523 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
21:03:15,524 INFO  [org.littlewings.servlet.async.AsyncBadDispatchServlet] (default task-1) do get
21:03:15,528 INFO  [org.littlewings.servlet.async.AsyncBadDispatchServlet] (EE-ManagedExecutorService-default-Thread-1) do task
21:03:15,529 INFO  [org.littlewings.servlet.async.AsyncBadDispatchServlet] (EE-ManagedExecutorService-default-Thread-1) do dispatch simple
21:03:15,533 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
21:03:15,535 INFO  [org.littlewings.servlet.async.AsyncBadDispatchServlet] (EE-ManagedExecutorService-default-Thread-1) error = UT010025: Async request already dispatched: java.lang.IllegalStateException: UT010025: Async request already dispatched
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.AsyncContextImpl.dispatch(AsyncContextImpl.java:218)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.AsyncContextImpl.dispatch(AsyncContextImpl.java:211)
        at deployment.ROOT.war//org.littlewings.servlet.async.AsyncBadDispatchServlet.lambda$doGet$0(AsyncBadDispatchServlet.java:43)
        at org.wildfly.concurrency@35.0.1.Final//org.jboss.as.ee.concurrent.ControlPointUtils$ControlledRunnable.run(ControlPointUtils.java:118)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.SecurityIdentity.runAsConsumer(SecurityIdentity.java:376)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAsConsumer(Scoped.java:112)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:60)
        at org.wildfly.concurrency@35.0.1.Final//org.jboss.as.ee.concurrent.SecurityIdentityUtils.lambda$doIdentityWrap$1(SecurityIdentityUtils.java:50)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at org.glassfish.jakarta.enterprise.concurrent//org.glassfish.enterprise.concurrent.internal.ManagedFutureTask.run(ManagedFutureTask.java:119)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)
        at org.glassfish.jakarta.enterprise.concurrent//org.glassfish.enterprise.concurrent.ManagedThreadFactoryImpl$ManagedThread.run(ManagedThreadFactoryImpl.java:322)


### 非同期Servlet+JSPへ
21:04:05,710 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
21:04:05,710 INFO  [org.littlewings.servlet.async.AsyncBadDispatchServlet] (default task-1) do get
21:04:05,712 INFO  [org.littlewings.servlet.async.AsyncBadDispatchServlet] (EE-ManagedExecutorService-default-Thread-3) do task
21:04:05,713 INFO  [org.littlewings.servlet.async.AsyncBadDispatchServlet] (EE-ManagedExecutorService-default-Thread-3) do dispatch simple
21:04:05,713 INFO  [org.littlewings.servlet.async.AsyncSupportedFilter] (default task-1) do filter / async supported
21:04:05,713 INFO  [org.littlewings.servlet.async.AsyncBadDispatchServlet] (EE-ManagedExecutorService-default-Thread-3) error = UT010025: Async request already dispatched: java.lang.IllegalStateException: UT010025: Async request already dispatched
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.AsyncContextImpl.dispatch(AsyncContextImpl.java:218)
        at io.undertow.servlet@2.3.18.Final//io.undertow.servlet.spec.AsyncContextImpl.dispatch(AsyncContextImpl.java:211)
        at deployment.ROOT.war//org.littlewings.servlet.async.AsyncBadDispatchServlet.lambda$doGet$0(AsyncBadDispatchServlet.java:43)
        at org.wildfly.concurrency@35.0.1.Final//org.jboss.as.ee.concurrent.ControlPointUtils$ControlledRunnable.run(ControlPointUtils.java:118)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.SecurityIdentity.runAsConsumer(SecurityIdentity.java:376)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAsConsumer(Scoped.java:112)
        at org.wildfly.security.elytron-base@2.6.0.Final//org.wildfly.security.auth.server.Scoped.runAs(Scoped.java:60)
        at org.wildfly.concurrency@35.0.1.Final//org.jboss.as.ee.concurrent.SecurityIdentityUtils.lambda$doIdentityWrap$1(SecurityIdentityUtils.java:50)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
        at org.glassfish.jakarta.enterprise.concurrent//org.glassfish.enterprise.concurrent.internal.ManagedFutureTask.run(ManagedFutureTask.java:119)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
        at java.base/java.lang.Thread.run(Thread.java:1583)
        at org.glassfish.jakarta.enterprise.concurrent//org.glassfish.enterprise.concurrent.ManagedThreadFactoryImpl$ManagedThread.run(ManagedThreadFactoryImpl.java:322)



## Apache Tomcat
### 非同期Servletへ
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-3] INFO org.littlewings.servlet.async.AsyncBadDispatchServlet - do get
[INFO] [pool-1-thread-1] INFO org.littlewings.servlet.async.AsyncBadDispatchServlet - do task
[INFO] [pool-1-thread-1] INFO org.littlewings.servlet.async.AsyncBadDispatchServlet - do dispatch simple
[INFO] [pool-1-thread-1] INFO org.littlewings.servlet.async.AsyncBadDispatchServlet - error = complete()の後、またはdispatch()メソッドのどれかが呼び出された不正なgetRequest()の呼び出し
[INFO] java.lang.IllegalStateException: complete()の後、またはdispatch()メソッドのどれかが呼び出された不正なgetRequest()の呼び出し
[INFO]  at org.apache.catalina.core.AsyncContextImpl.getRequest(AsyncContextImpl.java:213)
[INFO]  at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:176)
[INFO]  at org.littlewings.servlet.async.AsyncBadDispatchServlet.lambda$doGet$0(AsyncBadDispatchServlet.java:43)
[INFO]  at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
[INFO]  at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
[INFO]  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
[INFO]  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO] [http-nio-8080-exec-4] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported


### 非同期Servlet+JSPへ
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported
[INFO] [http-nio-8080-exec-5] INFO org.littlewings.servlet.async.AsyncBadDispatchServlet - do get
[INFO] [pool-1-thread-2] INFO org.littlewings.servlet.async.AsyncBadDispatchServlet - do task
[INFO] [pool-1-thread-2] INFO org.littlewings.servlet.async.AsyncBadDispatchServlet - do dispatch simple
[INFO] [pool-1-thread-2] INFO org.littlewings.servlet.async.AsyncBadDispatchServlet - error = complete()の後、またはdispatch()メソッドのどれかが呼び出された不正なgetRequest()の呼び出し
[INFO] java.lang.IllegalStateException: complete()の後、またはdispatch()メソッドのどれかが呼び出された不正なgetRequest()の呼び出し
[INFO]  at org.apache.catalina.core.AsyncContextImpl.getRequest(AsyncContextImpl.java:213)
[INFO]  at org.apache.catalina.core.AsyncContextImpl.dispatch(AsyncContextImpl.java:176)
[INFO]  at org.littlewings.servlet.async.AsyncBadDispatchServlet.lambda$doGet$0(AsyncBadDispatchServlet.java:43)
[INFO]  at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572)
[INFO]  at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)
[INFO]  at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)
[INFO]  at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)
[INFO]  at java.base/java.lang.Thread.run(Thread.java:1583)
[INFO] [http-nio-8080-exec-7] INFO org.littlewings.servlet.async.AsyncSupportedFilter - do filter / async supported

WildFlyApache Tomcatのどちらも2回目のAsyncContext#dispatchが呼び出されたところでIllegalStateException
スローされます。

少しソースコードを見る

非同期ServletからAsyncContext#dispatchでディスパッチすると、HTTPリクエストを処理するスレッドで動いていそうな
ことがわかりましたが、それをソースコードからも確認してみましょう。

Undertowの場合

Undertowの場合、dispatchメソッドの実体はこちらです。

https://github.com/undertow-io/undertow/blob/2.3.18.Final/servlet/src/main/java/io/undertow/servlet/spec/AsyncContextImpl.java#L214-L233

https://github.com/undertow-io/undertow/blob/2.3.18.Final/servlet/src/main/java/io/undertow/servlet/spec/AsyncContextImpl.java#L192-L207

ディスパッチしたリクエストはキューに入れられます。

https://github.com/undertow-io/undertow/blob/2.3.18.Final/servlet/src/main/java/io/undertow/servlet/spec/AsyncContextImpl.java#L431

https://github.com/undertow-io/undertow/blob/2.3.18.Final/servlet/src/main/java/io/undertow/servlet/spec/AsyncContextImpl.java#L537

そしてこのキューからリクエストを取り出し、Executorで処理するのですが

https://github.com/undertow-io/undertow/blob/2.3.18.Final/servlet/src/main/java/io/undertow/servlet/spec/AsyncContextImpl.java#L517-L520

ここで使われるExecutorの取得経路はAsyncContect#startと同じなので、結果的にワーカースレッド(Servlet
リクエストを処理するのと同じスレッドプール)を使うことになります。

https://github.com/undertow-io/undertow/blob/2.3.18.Final/servlet/src/main/java/io/undertow/servlet/spec/AsyncContextImpl.java#L295-L304

どうしてワーカースレッドになるのかは、このエントリーを書いた時にまとめています。

Jakarta Servletの非同期処理をWildFly 35、Apache Tomcat 10.1で試す - CLOVER🍀

Apache Tomcatの場合

Apache Tomcatの場合、dispatchメソッドについてはこのあたりを追っていきます。

https://github.com/apache/tomcat/blob/10.1.36/java/org/apache/catalina/core/AsyncContextImpl.java#L204

https://github.com/apache/tomcat/blob/10.1.36/java/org/apache/coyote/AbstractProcessor.java#L521-L526

AsyncStateMachineの状態的に問題がなければディスパッチが行われ

https://github.com/apache/tomcat/blob/10.1.36/java/org/apache/coyote/AbstractProcessor.java#L883

最終的にエンドポイントを処理するものと同じExecutorが使われることが確認できます。

https://github.com/apache/tomcat/blob/10.1.36/java/org/apache/tomcat/util/net/AbstractEndpoint.java#L1264

おわりに

WildFly 35.0.1.Final、Apache Tomcat 10.1.36を使って、Jakarta Servletの非同期処理でディスパッチをいろいろ試してみました。

およそ思ったとおりの動きだったのですが、ディスパッチ先でどのスレッドが使われるかはあまり考えていなかったので
結果を見てこの視点に気付かされました。

特に気にしていなかったのですが、なるほどなとは思いましたね。

あとはエラーハンドリングまわりを気にしておいた方がよさそうです。