You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2026/07/06 15:04:38 UTC

(skywalking-java) branch fix/13938-http-commons created (now 029ea90406)

This is an automated email from the ASF dual-hosted git repository.

wu-sheng pushed a change to branch fix/13938-http-commons
in repository https://gitbox.apache.org/repos/asf/skywalking-java.git


      at 029ea90406 Fix include_http_headers on Spring Boot 3.x/Jakarta, unify Tomcat/Jetty servlet plugins (#13938)

This branch includes the following new commits:

     new 029ea90406 Fix include_http_headers on Spring Boot 3.x/Jakarta, unify Tomcat/Jetty servlet plugins (#13938)

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(skywalking-java) 01/01: Fix include_http_headers on Spring Boot 3.x/Jakarta, unify Tomcat/Jetty servlet plugins (#13938)

Posted by wu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

wu-sheng pushed a commit to branch fix/13938-http-commons
in repository https://gitbox.apache.org/repos/asf/skywalking-java.git

commit 029ea90406fdc608926de20b027be62be97545b1
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Mon Jul 6 23:04:06 2026 +0800

    Fix include_http_headers on Spring Boot 3.x/Jakarta, unify Tomcat/Jetty servlet plugins (#13938)
    
    Add a shared servlet-commons module: a JDK-typed, namespace-agnostic servlet
    request/response wrapper that resolves javax.servlet vs jakarta.servlet at
    runtime through a single dispatch point. Refactor the Spring MVC commons onto
    it, removing the fragile static javax/jakarta detection that silently dropped
    plugin.http.include_http_headers on Jakarta (Spring Boot 3.x) applications.
    
    Merge the duplicated servlet plugin pairs, each now covering both namespaces:
    - tomcat-7.x-8.x + tomcat-10x  -> tomcat
    - jetty-server-9.x + jetty-server-11.x -> jetty-server
    Breaking change: the plugin definition names change accordingly; update any
    plugin.exclude_plugins (SW_EXCLUDE_PLUGINS) settings referencing the old names.
    
    Add E2E scenarios spring-boot-3.x (Boot 3 embedded Tomcat 10, jakarta) and
    spring-boot-2.x (Boot 2, javax mirror), both asserting http.headers and
    http.params; port the tomcat/jetty interceptor unit tests to the merged
    modules; bump jakarta framework versions (one per minor); update docs.
---
 .github/workflows/plugins-jdk17-test.1.yaml        |   1 +
 .github/workflows/plugins-test.2.yaml              |   1 +
 CHANGES.md                                         |   2 +
 .../jetty/v11/server/ForwardInterceptor.java       |  63 --------
 .../define/AbstractWitnessInstrumentation.java     |  39 -----
 .../jetty-plugin/jetty-server-9.x-plugin/pom.xml   |  45 ------
 .../plugin/jetty/v9/server/HandleInterceptor.java  |  90 ------------
 .../server/define/DispatcherInstrumentation.java   |  80 -----------
 .../v9/server/define/JettyInstrumentation.java     |  71 ---------
 .../pom.xml                                        |  17 ++-
 .../apm/plugin/jetty/server}/Constants.java        |   2 +-
 .../plugin/jetty}/server/ForwardInterceptor.java   |   9 +-
 .../plugin/jetty}/server/HandleInterceptor.java    |  24 ++--
 .../define/AbstractWitnessInstrumentation.java     |   8 +-
 .../server/define/DispatcherInstrumentation.java   |   4 +-
 .../jetty}/server/define/JettyInstrumentation.java |   4 +-
 .../src/main/resources/skywalking-plugin.def       |   5 +-
 .../jetty}/server/HandleInterceptorTest.java       |  17 ++-
 apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml    |   3 +-
 apm-sniffer/apm-sdk-plugin/pom.xml                 |   4 +-
 .../pom.xml                                        |  55 +++----
 .../apm/plugin/servlet/HttpRequestWrapper.java}    |  18 ++-
 .../apm/plugin/servlet/HttpRequestWrappers.java    | 158 +++++++++++++++++++++
 .../apm/plugin/servlet/HttpResponseWrapper.java}   |  24 ++--
 .../apm/plugin/servlet/HttpResponseWrappers.java   | 100 +++++++++++++
 .../plugin/servlet/HttpRequestWrappersTest.java    |  80 +++++++++++
 .../plugin/servlet/HttpResponseWrappersTest.java   |  65 +++++++++
 .../spring-plugins/mvc-annotation-commons/pom.xml  |  20 ++-
 .../mvc/commons/HttpServletRequestWrappers.java    | 112 ---------------
 .../apm/plugin/spring/mvc/commons/RequestUtil.java |  64 +--------
 .../interceptor/AbstractMethodInterceptor.java     |  76 ++--------
 .../ApplicationDispatcherInstrumentation.java      |  86 -----------
 .../tomcat10x/define/TomcatInstrumentation.java    | 100 -------------
 .../apm/plugin/tomcat78x/ForwardInterceptor.java   |  63 --------
 .../tomcat78x/TomcatExceptionInterceptor.java      |  45 ------
 .../plugin/tomcat78x/TomcatInvokeInterceptor.java  | 135 ------------------
 .../apm/plugin/tomcat78x/TomcatPluginConfig.java   |  43 ------
 .../{tomcat-10x-plugin => tomcat-plugin}/pom.xml   |  18 ++-
 .../skywalking/apm/plugin/tomcat}/Constants.java   |   2 +-
 .../apm/plugin/tomcat}/ForwardInterceptor.java     |   2 +-
 .../plugin/tomcat}/TomcatExceptionInterceptor.java |   2 +-
 .../plugin/tomcat}/TomcatInvokeInterceptor.java    |  21 +--
 .../apm/plugin/tomcat}/TomcatPluginConfig.java     |   2 +-
 .../ApplicationDispatcherInstrumentation.java      |   9 +-
 .../tomcat}/define/TomcatInstrumentation.java      |  13 +-
 .../src/main/resources/skywalking-plugin.def       |   5 +-
 .../tomcat}/TomcatInvokeInterceptorTest.java       |  16 ++-
 .../org.mockito.plugins.MockMaker                  |   0
 .../java-agent/Java-Plugin-Development-Guide.md    |   2 +-
 .../setup/service-agent/java-agent/Plugin-list.md  |   6 +-
 .../jersey-3.x-scenario/support-version.list       |   2 +-
 .../jetty-11.x-scenario/support-version.list       |   4 +-
 .../resteasy-6.x-scenario/support-version.list     |   2 +-
 .../resttemplate-6.x-scenario/bin/startup.sh       |   2 +-
 .../spring-6.x-scenario/config/expectedData.yaml   |   4 +
 .../spring-6.x-scenario/configuration.yml          |   4 +-
 .../spring-6.x-scenario/support-version.list       |   2 +-
 .../spring-boot-2.x-scenario/bin/startup.sh        |   7 +-
 .../config/expectedData.yaml                       |  74 +++++-----
 .../spring-boot-2.x-scenario/configuration.yml     |   8 +-
 .../scenarios/spring-boot-2.x-scenario/pom.xml     | 114 +++++++++++++++
 .../src/main/assembly/assembly.xml                 |  43 +++---
 .../skywalking/apm/testcase/Application.java       |  23 ++-
 .../skywalking/apm/testcase/entity/User.java       |  36 +++--
 .../testcase/implinterface/TestCaseController.java |  26 ++--
 .../testcase/implinterface/TestCaseInterface.java  |  24 ++--
 .../apm/testcase/inherit/ChildController.java      |  14 +-
 .../apm/testcase/inherit/ParentController.java     |  25 ++--
 .../apm/testcase/restapi/RestCaseController.java   |  77 ++++++++++
 .../resttemplate/RestTemplateController.java       |  85 +++++++++++
 .../apm/testcase/spring3/CaseController.java       |  30 ++--
 .../spring3/component/TestComponentBean.java       |  15 +-
 .../testcase/spring3/dao/TestRepositoryBean.java   |  15 +-
 .../testcase/spring3/service/TestServiceBean.java  |  29 ++--
 .../src/main/resources/application.yml}            |   7 +-
 .../src/main/resources/log4j2.xml                  |  36 ++---
 .../support-version.list                           |  12 +-
 .../spring-boot-3.x-scenario/bin/startup.sh        |   7 +-
 .../config/expectedData.yaml                       |  74 +++++-----
 .../spring-boot-3.x-scenario/configuration.yml     |   8 +-
 .../scenarios/spring-boot-3.x-scenario/pom.xml     | 125 ++++++++++++++++
 .../src/main/assembly/assembly.xml                 |  43 +++---
 .../skywalking/apm/testcase/Application.java       |  23 ++-
 .../skywalking/apm/testcase/entity/User.java       |  36 +++--
 .../testcase/implinterface/TestCaseController.java |  26 ++--
 .../testcase/implinterface/TestCaseInterface.java  |  24 ++--
 .../apm/testcase/inherit/ChildController.java      |  14 +-
 .../apm/testcase/inherit/ParentController.java     |  25 ++--
 .../apm/testcase/restapi/RestCaseController.java   |  77 ++++++++++
 .../resttemplate/RestTemplateController.java       |  85 +++++++++++
 .../apm/testcase/spring3/CaseController.java       |  30 ++--
 .../spring3/component/TestComponentBean.java       |  15 +-
 .../testcase/spring3/dao/TestRepositoryBean.java   |  15 +-
 .../testcase/spring3/service/TestServiceBean.java  |  29 ++--
 .../src/main/resources/application.yml}            |   7 +-
 .../src/main/resources/log4j2.xml                  |  36 ++---
 .../support-version.list                           |   9 +-
 .../undertow-2.3.x-scenario/support-version.list   |   5 +-
 98 files changed, 1630 insertions(+), 1634 deletions(-)

diff --git a/.github/workflows/plugins-jdk17-test.1.yaml b/.github/workflows/plugins-jdk17-test.1.yaml
index ed6efcfef4..6be997dc0e 100644
--- a/.github/workflows/plugins-jdk17-test.1.yaml
+++ b/.github/workflows/plugins-jdk17-test.1.yaml
@@ -71,6 +71,7 @@ jobs:
       matrix:
         case:
           - spring-6.x-scenario
+          - spring-boot-3.x-scenario
           - resteasy-6.x-scenario
           - gateway-4.x-scenario
           - gateway-4.1.2.x-scenario
diff --git a/.github/workflows/plugins-test.2.yaml b/.github/workflows/plugins-test.2.yaml
index 1bbf07ef31..042a14d947 100644
--- a/.github/workflows/plugins-test.2.yaml
+++ b/.github/workflows/plugins-test.2.yaml
@@ -74,6 +74,7 @@ jobs:
           - rabbitmq-scenario
           - redisson-scenario
           - resttemplate-4.x-scenario
+          - spring-boot-2.x-scenario
           - servicecomb-1.x-scenario
           - servicecomb-2.x-scenario
           - shardingsphere-3.x-scenario
diff --git a/CHANGES.md b/CHANGES.md
index 8136757432..9f994787ff 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -5,6 +5,8 @@ Release Notes.
 9.7.0
 ------------------
 
+* Fix `plugin.http.include_http_headers` not working on Spring Boot 3.x / Jakarta EE (apache/skywalking#13938).
+* Unify the Tomcat plugins into a single `tomcat` plugin (Tomcat 7 - 10) and the Jetty server plugins into a single `jetty-server` plugin (Jetty 9 - 11), each supporting both `javax.servlet` and `jakarta.servlet`. Breaking change: plugin names `tomcat-7.x/8.x` and `tomcat-10.x` are replaced by `tomcat`, and `jetty-server-9.x` and `jetty-server-11.x` by `jetty-server`; update `plugin.exclude_plugins` if you reference the old names.
 * Added support for Lettuce reactive Redis commands.
 * Add Spring AI 1.x plugin and GenAI layer.
 * Fix httpclient-5.x plugin injecting sw8 propagation headers into ClickHouse HTTP requests (port 8123), causing HTTP 400. Add `PROPAGATION_EXCLUDE_PORTS` config to skip tracing (including header injection) for specified ports in the classic client interceptor.
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/ForwardInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/ForwardInterceptor.java
deleted file mode 100644
index f98e15c8af..0000000000
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/ForwardInterceptor.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- *
- */
-
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
-
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
-import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
-
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-
-public class ForwardInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
-
-    @Override
-    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-        MethodInterceptResult result) throws Throwable {
-        if (ContextManager.isActive()) {
-            AbstractSpan abstractTracingSpan = ContextManager.activeSpan();
-            Map<String, String> eventMap = new HashMap<String, String>();
-            eventMap.put("forward-url", (String) objInst.getSkyWalkingDynamicField());
-            abstractTracingSpan.log(System.currentTimeMillis(), eventMap);
-            ContextManager.getRuntimeContext().put(Constants.FORWARD_REQUEST_FLAG, true);
-        }
-    }
-
-    @Override
-    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-        Object ret) throws Throwable {
-        return ret;
-    }
-
-    @Override
-    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
-        Class<?>[] argumentsTypes, Throwable t) {
-
-    }
-
-    @Override
-    public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
-        objInst.setSkyWalkingDynamicField(allArguments[2]);
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/AbstractWitnessInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/AbstractWitnessInstrumentation.java
deleted file mode 100644
index ae0eef39f3..0000000000
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/AbstractWitnessInstrumentation.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- *
- */
-
-package org.apache.skywalking.apm.plugin.jetty.v11.server.define;
-
-import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
-
-import java.util.Collections;
-import java.util.List;
-
-import static net.bytebuddy.matcher.ElementMatchers.named;
-import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
-
-public abstract class AbstractWitnessInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
-    @Override
-    protected List<WitnessMethod> witnessMethods() {
-        return Collections.singletonList(new WitnessMethod(
-                "org.eclipse.jetty.server.Handler",
-                named("handle").and(takesArgument(2, named("jakarta.servlet.http.HttpServletRequest")))
-        ));
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/pom.xml
deleted file mode 100644
index d4602b83c4..0000000000
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/pom.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<!--
-  ~ Licensed to the Apache Software Foundation (ASF) under one or more
-  ~ contributor license agreements.  See the NOTICE file distributed with
-  ~ this work for additional information regarding copyright ownership.
-  ~ The ASF licenses this file to You under the Apache License, Version 2.0
-  ~ (the "License"); you may not use this file except in compliance with
-  ~ the License.  You may obtain a copy of the License at
-  ~
-  ~     http://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  ~
-  -->
-
-<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">
-    <parent>
-        <artifactId>jetty-plugins</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>9.7.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>apm-jetty-server-9.x-plugin</artifactId>
-    <packaging>jar</packaging>
-
-    <name>jetty-server-9.x-plugin</name>
-    <url>http://maven.apache.org</url>
-
-    <properties>
-        <jetty-server.version>9.0.0.v20130308</jetty-server.version>
-    </properties>
-
-    <dependencies>
-        <dependency>
-            <groupId>org.eclipse.jetty</groupId>
-            <artifactId>jetty-server</artifactId>
-            <version>${jetty-server.version}</version>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-</project>
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptor.java
deleted file mode 100644
index 25006dd14c..0000000000
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptor.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.plugin.jetty.v9.server;
-
-import java.lang.reflect.Method;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.skywalking.apm.agent.core.context.CarrierItem;
-import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
-import org.apache.skywalking.apm.agent.core.context.tag.Tags;
-import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
-import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
-import org.apache.skywalking.apm.agent.core.util.MethodUtil;
-import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
-import org.eclipse.jetty.server.HttpChannel;
-
-public class HandleInterceptor implements InstanceMethodsAroundInterceptor {
-
-    private static boolean IS_SERVLET_GET_STATUS_METHOD_EXIST;
-    private static final String SERVLET_RESPONSE_CLASS = "javax.servlet.http.HttpServletResponse";
-    private static final String GET_STATUS_METHOD = "getStatus";
-
-    static {
-        IS_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(HandleInterceptor.class.getClassLoader(), SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD);
-    }
-
-    @Override
-    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-        MethodInterceptResult result) throws Throwable {
-        HttpChannel httpChannel = (HttpChannel) objInst;
-        HttpServletRequest servletRequest = httpChannel.getRequest();
-
-        ContextCarrier contextCarrier = new ContextCarrier();
-
-        CarrierItem next = contextCarrier.items();
-        while (next.hasNext()) {
-            next = next.next();
-            next.setHeadValue(servletRequest.getHeader(next.getHeadKey()));
-        }
-
-        AbstractSpan span = ContextManager.createEntrySpan(servletRequest.getRequestURI(), contextCarrier);
-        Tags.URL.set(span, servletRequest.getRequestURL().toString());
-        Tags.HTTP.METHOD.set(span, servletRequest.getMethod());
-        span.setComponent(ComponentsDefine.JETTY_SERVER);
-        SpanLayer.asHttp(span);
-    }
-
-    @Override
-    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-        Object ret) throws Throwable {
-        HttpChannel httpChannel = (HttpChannel) objInst;
-        HttpServletResponse servletResponse = httpChannel.getResponse();
-        AbstractSpan span = ContextManager.activeSpan();
-        if (IS_SERVLET_GET_STATUS_METHOD_EXIST) {
-            Tags.HTTP_RESPONSE_STATUS_CODE.set(span, servletResponse.getStatus());
-            if (servletResponse.getStatus() >= 400) {
-                span.errorOccurred();
-            }
-        }
-        ContextManager.stopSpan();
-        ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG);
-        return ret;
-    }
-
-    @Override
-    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
-        Class<?>[] argumentsTypes, Throwable t) {
-        ContextManager.activeSpan().log(t);
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/DispatcherInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/DispatcherInstrumentation.java
deleted file mode 100644
index 343e7d28c8..0000000000
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/DispatcherInstrumentation.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- *
- */
-
-package org.apache.skywalking.apm.plugin.jetty.v9.server.define;
-
-import net.bytebuddy.description.method.MethodDescription;
-import net.bytebuddy.matcher.ElementMatcher;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
-
-import static net.bytebuddy.matcher.ElementMatchers.named;
-import static org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
-import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
-
-public class DispatcherInstrumentation extends AbstractWitnessInstrumentation {
-
-    private static final String ENHANCE_CLASS = "org.eclipse.jetty.server.Dispatcher";
-    public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.jetty.v9.server.ForwardInterceptor";
-
-    @Override
-    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
-        return new ConstructorInterceptPoint[]{
-                new ConstructorInterceptPoint() {
-                    @Override
-                    public ElementMatcher<MethodDescription> getConstructorMatcher() {
-                        return takesArgumentWithType(2, "java.lang.String");
-                    }
-
-                    @Override
-                    public String getConstructorInterceptor() {
-                        return INTERCEPT_CLASS;
-                    }
-                }
-        };
-    }
-
-    @Override
-    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
-        return new InstanceMethodsInterceptPoint[]{
-                new InstanceMethodsInterceptPoint() {
-                    @Override
-                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
-                        return named("forward");
-                    }
-
-                    @Override
-                    public String getMethodsInterceptor() {
-                        return INTERCEPT_CLASS;
-                    }
-
-                    @Override
-                    public boolean isOverrideArgs() {
-                        return false;
-                    }
-                }
-        };
-    }
-
-    @Override
-    protected ClassMatch enhanceClass() {
-        return byName(ENHANCE_CLASS);
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/JettyInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/JettyInstrumentation.java
deleted file mode 100644
index 59ac7307e6..0000000000
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/JettyInstrumentation.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.plugin.jetty.v9.server.define;
-
-import net.bytebuddy.description.method.MethodDescription;
-import net.bytebuddy.matcher.ElementMatcher;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
-import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
-
-import static net.bytebuddy.matcher.ElementMatchers.named;
-
-/**
- * {@link JettyInstrumentation} enhance the <code>handle</code> method in <code>org.eclipse.jetty.server.handler.HandlerList</code>
- * by <code>HandleInterceptor</code>
- */
-public class JettyInstrumentation extends AbstractWitnessInstrumentation {
-
-    private static final String ENHANCE_CLASS = "org.eclipse.jetty.server.HttpChannel";
-    private static final String ENHANCE_METHOD = "handle";
-    private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jetty.v9.server.HandleInterceptor";
-
-    @Override
-    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
-        return new ConstructorInterceptPoint[0];
-    }
-
-    @Override
-    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
-        return new InstanceMethodsInterceptPoint[]{
-                new InstanceMethodsInterceptPoint() {
-                    @Override
-                    public ElementMatcher<MethodDescription> getMethodsMatcher() {
-                        return named(ENHANCE_METHOD);
-                    }
-
-                    @Override
-                    public String getMethodsInterceptor() {
-                        return INTERCEPTOR_CLASS;
-                    }
-
-                    @Override
-                    public boolean isOverrideArgs() {
-                        return false;
-                    }
-                }
-        };
-    }
-
-    @Override
-    protected ClassMatch enhanceClass() {
-        return NameMatch.byName(ENHANCE_CLASS);
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/pom.xml
similarity index 67%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/pom.xml
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/pom.xml
index c70f0ddd37..8477c1b9b8 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/pom.xml
@@ -24,12 +24,19 @@
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>apm-jetty-server-11.x-plugin</artifactId>
+    <artifactId>apm-jetty-server-plugin</artifactId>
     <packaging>jar</packaging>
 
-    <name>jetty-server-11.x-plugin</name>
+    <name>jetty-server-plugin</name>
     <url>http://maven.apache.org</url>
 
+    <!--
+      Unified Jetty server plugin covering Jetty 9/10 (javax.servlet) and Jetty 11 (jakarta.servlet).
+      The interceptor reads request/response through the shared servlet-commons wrapper off the
+      concrete org.eclipse.jetty.server.Request/Response, so a single plugin activates on all three
+      via the HttpChannel enhance target plus a namespace-either Handler#handle witness. Jetty 12
+      removed HttpChannel and needs a separate plugin.
+    -->
     <properties>
         <jetty-server.version>11.0.15</jetty-server.version>
     </properties>
@@ -41,5 +48,11 @@
             <version>${jetty-server.version}</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>apm-servlet-commons</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 </project>
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/Constants.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/Constants.java
similarity index 94%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/Constants.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/Constants.java
index 3aa2d92ae3..22948d4a7d 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/Constants.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/Constants.java
@@ -17,7 +17,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.tomcat10x;
+package org.apache.skywalking.apm.plugin.jetty.server;
 
 public class Constants {
     public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/ForwardInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/ForwardInterceptor.java
similarity index 97%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/ForwardInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/ForwardInterceptor.java
index 669fae1770..0855f9961a 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/ForwardInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/ForwardInterceptor.java
@@ -17,11 +17,8 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v9.server;
+package org.apache.skywalking.apm.plugin.jetty.server;
 
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
 import org.apache.skywalking.apm.agent.core.context.ContextManager;
 import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
@@ -29,6 +26,10 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceC
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
 
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
 public class ForwardInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
 
     @Override
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/HandleInterceptor.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptor.java
similarity index 75%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/HandleInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptor.java
index a8f663a917..386587d270 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/HandleInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptor.java
@@ -16,10 +16,8 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
+package org.apache.skywalking.apm.plugin.jetty.server;
 
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
 import org.apache.skywalking.apm.agent.core.context.CarrierItem;
 import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
 import org.apache.skywalking.apm.agent.core.context.ContextManager;
@@ -30,6 +28,10 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedI
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
 import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrapper;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrappers;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrapper;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrappers;
 import org.eclipse.jetty.server.HttpChannel;
 
 import java.lang.reflect.Method;
@@ -40,7 +42,9 @@ public class HandleInterceptor implements InstanceMethodsAroundInterceptor {
     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                              MethodInterceptResult result) throws Throwable {
         HttpChannel httpChannel = (HttpChannel) objInst;
-        HttpServletRequest servletRequest = httpChannel.getRequest();
+        // getRequest() returns the concrete org.eclipse.jetty.server.Request; the wrapper resolves the
+        // javax vs jakarta servlet namespace at runtime, keeping this interceptor namespace-neutral.
+        HttpRequestWrapper servletRequest = HttpRequestWrappers.wrap(httpChannel.getRequest());
 
         ContextCarrier contextCarrier = new ContextCarrier();
 
@@ -61,11 +65,15 @@ public class HandleInterceptor implements InstanceMethodsAroundInterceptor {
     public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                               Object ret) throws Throwable {
         HttpChannel httpChannel = (HttpChannel) objInst;
-        HttpServletResponse servletResponse = httpChannel.getResponse();
         AbstractSpan span = ContextManager.activeSpan();
-        Tags.HTTP_RESPONSE_STATUS_CODE.set(span, servletResponse.getStatus());
-        if (servletResponse.getStatus() >= 400) {
-            span.errorOccurred();
+        // A null wrapper means getStatus() is unavailable (pre-Servlet-3.0), matching the historical guard.
+        HttpResponseWrapper servletResponse = HttpResponseWrappers.wrap(httpChannel.getResponse());
+        if (servletResponse != null) {
+            int statusCode = servletResponse.getStatus();
+            Tags.HTTP_RESPONSE_STATUS_CODE.set(span, statusCode);
+            if (statusCode >= 400) {
+                span.errorOccurred();
+            }
         }
         ContextManager.stopSpan();
         ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG);
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/AbstractWitnessInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/AbstractWitnessInstrumentation.java
similarity index 75%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/AbstractWitnessInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/AbstractWitnessInstrumentation.java
index 9ed1aba497..3a0993fee7 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/define/AbstractWitnessInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/AbstractWitnessInstrumentation.java
@@ -17,7 +17,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v9.server.define;
+package org.apache.skywalking.apm.plugin.jetty.server.define;
 
 import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
@@ -31,9 +31,13 @@ import static net.bytebuddy.matcher.ElementMatchers.takesArgument;
 public abstract class AbstractWitnessInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
     @Override
     protected List<WitnessMethod> witnessMethods() {
+        // Match the Jetty Handler#handle whose request argument is either the javax (Jetty 9/10) or the
+        // jakarta (Jetty 11) servlet namespace, so a single merged plugin activates on both. A single
+        // Jetty distribution carries only one namespace, so exactly one branch matches at runtime.
         return Collections.singletonList(new WitnessMethod(
                 "org.eclipse.jetty.server.Handler",
-                named("handle").and(takesArgument(2, named("javax.servlet.http.HttpServletRequest")))
+                named("handle").and(takesArgument(2, named("javax.servlet.http.HttpServletRequest")
+                        .or(named("jakarta.servlet.http.HttpServletRequest"))))
         ));
     }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/DispatcherInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/DispatcherInstrumentation.java
similarity index 96%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/DispatcherInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/DispatcherInstrumentation.java
index d843ae629f..ba468ad1b3 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/DispatcherInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/DispatcherInstrumentation.java
@@ -17,7 +17,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v11.server.define;
+package org.apache.skywalking.apm.plugin.jetty.server.define;
 
 import net.bytebuddy.description.method.MethodDescription;
 import net.bytebuddy.matcher.ElementMatcher;
@@ -32,7 +32,7 @@ import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName
 public class DispatcherInstrumentation extends AbstractWitnessInstrumentation {
 
     private static final String ENHANCE_CLASS = "org.eclipse.jetty.server.Dispatcher";
-    public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.jetty.v11.server.ForwardInterceptor";
+    public static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.jetty.server.ForwardInterceptor";
 
     @Override
     public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/JettyInstrumentation.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/JettyInstrumentation.java
similarity index 96%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/JettyInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/JettyInstrumentation.java
index 417dc67df3..1c8eb083ac 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/define/JettyInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/server/define/JettyInstrumentation.java
@@ -16,7 +16,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v11.server.define;
+package org.apache.skywalking.apm.plugin.jetty.server.define;
 
 import net.bytebuddy.description.method.MethodDescription;
 import net.bytebuddy.matcher.ElementMatcher;
@@ -35,7 +35,7 @@ public class JettyInstrumentation extends AbstractWitnessInstrumentation {
 
     private static final String ENHANCE_CLASS = "org.eclipse.jetty.server.HttpChannel";
     private static final String ENHANCE_METHOD = "handle";
-    private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jetty.v11.server" +
+    private static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.jetty.server" +
             ".HandleInterceptor";
 
     @Override
diff --git a/test/plugin/scenarios/spring-6.x-scenario/support-version.list b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/resources/skywalking-plugin.def
similarity index 81%
copy from test/plugin/scenarios/spring-6.x-scenario/support-version.list
copy to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/resources/skywalking-plugin.def
index c96f0b4304..f54cd54edb 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/support-version.list
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/main/resources/skywalking-plugin.def
@@ -14,6 +14,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-6.0.4
-6.1.0
-6.1.1
+jetty-server=org.apache.skywalking.apm.plugin.jetty.server.define.JettyInstrumentation
+jetty-server=org.apache.skywalking.apm.plugin.jetty.server.define.DispatcherInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptorTest.java
similarity index 89%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptorTest.java
rename to apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptorTest.java
index f4c8fef0dd..77100bf9d0 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/v9/server/HandleInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-plugin/src/test/java/org/apache/skywalking/apm/plugin/jetty/server/HandleInterceptorTest.java
@@ -16,7 +16,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v9.server;
+package org.apache.skywalking.apm.plugin.jetty.server;
 
 import static org.apache.skywalking.apm.agent.test.tools.SpanAssert.assertComponent;
 import static org.hamcrest.CoreMatchers.is;
@@ -44,7 +44,6 @@ import org.eclipse.jetty.io.EndPoint;
 import org.eclipse.jetty.server.Connector;
 import org.eclipse.jetty.server.HttpChannel;
 import org.eclipse.jetty.server.HttpConfiguration;
-import org.eclipse.jetty.server.HttpInput;
 import org.eclipse.jetty.server.HttpTransport;
 import org.eclipse.jetty.server.Request;
 import org.eclipse.jetty.server.Response;
@@ -87,6 +86,7 @@ public class HandleInterceptorTest {
         jettyInvokeInterceptor = new HandleInterceptor();
         when(request.getRequestURI()).thenReturn("/test/testRequestURL");
         when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080/test/testRequestURL"));
+        when(request.getMethod()).thenReturn("GET");
         when(response.getStatus()).thenReturn(200);
         when(service.getResponse()).thenReturn(response);
         when(service.getRequest()).thenReturn(request);
@@ -152,11 +152,18 @@ public class HandleInterceptorTest {
         SpanAssert.assertLayer(span, SpanLayer.HTTP);
     }
 
-    public static class MockService extends HttpChannel implements EnhancedInstance {
+    /**
+     * The merged {@link HandleInterceptor} casts the enhanced instance to the concrete Jetty
+     * {@link HttpChannel} and reads the request/response through the servlet-commons wrappers, so the
+     * mock target must be a Jetty 11 (jakarta) {@link HttpChannel} whose {@link #getRequest()} /
+     * {@link #getResponse()} return jakarta servlet request/response objects. Declared abstract to
+     * skip Jetty 11 {@code HttpChannel}'s abstract members, which Mockito stubs automatically.
+     */
+    public abstract static class MockService extends HttpChannel implements EnhancedInstance {
 
         public MockService(Connector connector, HttpConfiguration configuration, EndPoint endPoint,
-            HttpTransport transport, HttpInput input) {
-            super(connector, configuration, endPoint, transport, input);
+            HttpTransport transport) {
+            super(connector, configuration, endPoint, transport);
         }
 
         @Override
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml
index 0d051bd4c0..1ac21fb14d 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/jetty-plugin/pom.xml
@@ -29,9 +29,8 @@
     <artifactId>jetty-plugins</artifactId>
     <modules>
         <module>jetty-client-9.x-plugin</module>
-        <module>jetty-server-9.x-plugin</module>
         <module>jetty-client-9.0-plugin</module>
-        <module>jetty-server-11.x-plugin</module>
+        <module>jetty-server-plugin</module>
         <module>jetty-client-11.x-plugin</module>
     </modules>
     <packaging>pom</packaging>
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index 5d09bd0957..829d63dd84 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -30,10 +30,10 @@
     <modules>
         <module>dubbo-plugin</module>
         <module>jdbc-commons</module>
+        <module>servlet-commons</module>
         <module>httpClient-4.x-plugin</module>
         <module>redisson-3.x-plugin</module>
-        <module>tomcat-7.x-8.x-plugin</module>
-        <module>tomcat-10x-plugin</module>
+        <module>tomcat-plugin</module>
         <module>motan-plugin</module>
         <module>mongodb-3.x-plugin</module>
         <module>mongodb-4.x-plugin</module>
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/servlet-commons/pom.xml
similarity index 50%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/pom.xml
rename to apm-sniffer/apm-sdk-plugin/servlet-commons/pom.xml
index 0763bcca65..55fc22ab3e 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/pom.xml
@@ -18,52 +18,57 @@
 
 <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">
     <parent>
-        <artifactId>apm-sdk-plugin</artifactId>
         <groupId>org.apache.skywalking</groupId>
+        <artifactId>apm-sdk-plugin</artifactId>
         <version>9.7.0-SNAPSHOT</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>tomcat-7.x-8.x-plugin</artifactId>
+    <artifactId>apm-servlet-commons</artifactId>
     <packaging>jar</packaging>
 
-    <name>tomcat-7.x-8.x-plugin</name>
-    <url>http://maven.apache.org</url>
+    <name>servlet-commons</name>
 
     <properties>
-        <tomcat.version>8.0.36</tomcat.version>
-        <junit.version>4.12</junit.version>
-        <apache-httpclient.version>4.5.2</apache-httpclient.version>
+        <javax-servlet-api.version>3.0.1</javax-servlet-api.version>
+        <jakarta-servlet-api.version>6.0.0</jakarta-servlet-api.version>
     </properties>
 
+    <!--
+      A shared, plugin-agnostic library (no skywalking-plugin.def) providing a JDK-typed,
+      namespace-agnostic view over the servlet HTTP request/response, so servlet plugins can
+      handle both javax.servlet and jakarta.servlet through a single runtime dispatch point.
+      Both servlet APIs are 'provided': only one is present in any given application at runtime;
+      the factory selects the live one. Consumed by servlet plugins at 'provided' scope — this
+      module ships its own jar into skywalking-agent/plugins (via the inherited antrun copy),
+      so its classes are visible to every plugin through the AgentClassLoader at runtime.
+    -->
     <dependencies>
         <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>org.apache.tomcat.embed</groupId>
-            <artifactId>tomcat-embed-core</artifactId>
-            <version>${tomcat.version}</version>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>${javax-servlet-api.version}</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.tomcat.embed</groupId>
-            <artifactId>tomcat-embed-logging-juli</artifactId>
-            <version>${tomcat.version}</version>
-            <scope>test</scope>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+            <version>${jakarta-servlet-api.version}</version>
+            <scope>provided</scope>
         </dependency>
+        <!--
+          Both servlet APIs are on the TEST classpath (provided scope), which is exactly the #13938
+          trigger: both javax and jakarta present at once. The unit tests assert wrap() selects the
+          live namespace, guarding against a regression of the old exclusive-detection defect.
+        -->
         <dependency>
-            <groupId>org.apache.tomcat.embed</groupId>
-            <artifactId>tomcat-embed-jasper</artifactId>
-            <version>${tomcat.version}</version>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient</artifactId>
-            <version>${apache-httpclient.version}</version>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrapper.java
similarity index 62%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrapper.java
index d258f7a5f2..eee5d80dfe 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrapper.java
@@ -16,22 +16,32 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package org.apache.skywalking.apm.plugin.servlet;
 
 import java.util.Enumeration;
 import java.util.Map;
 
-public interface HttpServletRequestWrapper {
+/**
+ * A namespace-agnostic view over a servlet HTTP request. It abstracts away the javax.servlet vs
+ * jakarta.servlet split so servlet plugin code can be written once. Obtain instances via
+ * {@link HttpRequestWrappers#wrap(Object)}.
+ * <p>
+ * The method set is the union of what every servlet plugin actually reads; it intentionally does
+ * not expose cookies, sessions, multipart parts or the servlet context, none of which are collected.
+ */
+public interface HttpRequestWrapper {
 
     String getHeader(String name);
 
+    Enumeration<String> getHeaders(String name);
+
     String getMethod();
 
+    String getRequestURI();
+
     StringBuffer getRequestURL();
 
     String getRemoteHost();
 
     Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
 }
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappers.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappers.java
new file mode 100644
index 0000000000..6b35d9925b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappers.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+import java.util.Enumeration;
+import java.util.Map;
+
+/**
+ * Factory producing a {@link HttpRequestWrapper} from either a {@code javax.servlet} or a
+ * {@code jakarta.servlet} {@code HttpServletRequest}, selected at runtime by the concrete type of
+ * the argument. Both servlet namespaces may be present on the classpath at once (e.g. a Jakarta
+ * application that also carries {@code javax.servlet-api} transitively); the flags below are
+ * computed independently so the live request type — not classpath presence order — decides.
+ * <p>
+ * CLASSLOADING INVARIANT — DO NOT VIOLATE: every {@code javax}/{@code jakarta} reference lives
+ * inside its own nested wrapper class and is reached only through its {@link #IS_JAVAX} /
+ * {@link #IS_JAKARTA} flag guarded by a {@code &&} short-circuit. Never move a servlet type into
+ * {@link #wrap(Object)}'s shared body, never widen a method descriptor of this class to a servlet
+ * type, and never add a typed public {@code wrap(javax...)}/{@code wrap(jakarta...)} overload. Any
+ * of those makes the JVM eagerly resolve an absent namespace and reintroduces
+ * {@code NoClassDefFoundError} in single-namespace applications. Lazy constant-pool resolution
+ * keeps the guarded-but-unexecuted branch safe.
+ */
+public final class HttpRequestWrappers {
+
+    private static final boolean IS_JAVAX = classExists("javax.servlet.http.HttpServletRequest");
+    private static final boolean IS_JAKARTA = classExists("jakarta.servlet.http.HttpServletRequest");
+
+    private HttpRequestWrappers() {
+    }
+
+    /**
+     * @param request any object; typically the servlet request captured by a plugin.
+     * @return a wrapper when {@code request} is a javax or jakarta {@code HttpServletRequest}, or
+     * {@code null} otherwise (e.g. a reactive request or an unrecognized type), letting the caller
+     * fall through to its own non-servlet handling.
+     */
+    public static HttpRequestWrapper wrap(Object request) {
+        if (IS_JAVAX && request instanceof javax.servlet.http.HttpServletRequest) {
+            return new JavaxHttpServletRequest((javax.servlet.http.HttpServletRequest) request);
+        }
+        if (IS_JAKARTA && request instanceof jakarta.servlet.http.HttpServletRequest) {
+            return new JakartaHttpServletRequest((jakarta.servlet.http.HttpServletRequest) request);
+        }
+        return null;
+    }
+
+    private static boolean classExists(String className) {
+        try {
+            Class.forName(className, false, HttpRequestWrappers.class.getClassLoader());
+            return true;
+        } catch (Throwable ignore) {
+            return false;
+        }
+    }
+
+    private static final class JavaxHttpServletRequest implements HttpRequestWrapper {
+        private final javax.servlet.http.HttpServletRequest request;
+
+        private JavaxHttpServletRequest(javax.servlet.http.HttpServletRequest request) {
+            this.request = request;
+        }
+
+        @Override
+        public String getHeader(String name) {
+            return request.getHeader(name);
+        }
+
+        @Override
+        public Enumeration<String> getHeaders(String name) {
+            return request.getHeaders(name);
+        }
+
+        @Override
+        public String getMethod() {
+            return request.getMethod();
+        }
+
+        @Override
+        public String getRequestURI() {
+            return request.getRequestURI();
+        }
+
+        @Override
+        public StringBuffer getRequestURL() {
+            return request.getRequestURL();
+        }
+
+        @Override
+        public String getRemoteHost() {
+            return request.getRemoteHost();
+        }
+
+        @Override
+        public Map<String, String[]> getParameterMap() {
+            return request.getParameterMap();
+        }
+    }
+
+    private static final class JakartaHttpServletRequest implements HttpRequestWrapper {
+        private final jakarta.servlet.http.HttpServletRequest request;
+
+        private JakartaHttpServletRequest(jakarta.servlet.http.HttpServletRequest request) {
+            this.request = request;
+        }
+
+        @Override
+        public String getHeader(String name) {
+            return request.getHeader(name);
+        }
+
+        @Override
+        public Enumeration<String> getHeaders(String name) {
+            return request.getHeaders(name);
+        }
+
+        @Override
+        public String getMethod() {
+            return request.getMethod();
+        }
+
+        @Override
+        public String getRequestURI() {
+            return request.getRequestURI();
+        }
+
+        @Override
+        public StringBuffer getRequestURL() {
+            return request.getRequestURL();
+        }
+
+        @Override
+        public String getRemoteHost() {
+            return request.getRemoteHost();
+        }
+
+        @Override
+        public Map<String, String[]> getParameterMap() {
+            return request.getParameterMap();
+        }
+    }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrapper.java
similarity index 67%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrapper.java
index d258f7a5f2..b31ded6456 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrapper.java
@@ -16,22 +16,14 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package org.apache.skywalking.apm.plugin.servlet;
 
-import java.util.Enumeration;
-import java.util.Map;
-
-public interface HttpServletRequestWrapper {
-
-    String getHeader(String name);
-
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
+/**
+ * A namespace-agnostic view over a servlet HTTP response. Obtain instances via
+ * {@link HttpResponseWrappers#wrap(Object)}. Only the response status code is exposed — the sole
+ * response datum servlet plugins collect.
+ */
+public interface HttpResponseWrapper {
 
-    public Enumeration<String> getHeaders(String name);
+    int getStatus();
 }
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappers.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappers.java
new file mode 100644
index 0000000000..4a85c44bac
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/main/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappers.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+/**
+ * Factory producing a {@link HttpResponseWrapper} from either a {@code javax.servlet} or a
+ * {@code jakarta.servlet} {@code HttpServletResponse}, selected at runtime.
+ * <p>
+ * Detection deliberately checks that the {@code getStatus()} method exists (added in Servlet 3.0),
+ * not merely that the response class is present, preserving the guard for pre-3.0 containers where
+ * status is unavailable. {@link #servletStatusSupported()} lets a caller gate a non-servlet (e.g.
+ * reactive) status fallback on the same capability.
+ * <p>
+ * The same CLASSLOADING INVARIANT as {@link HttpRequestWrappers} applies: keep every
+ * {@code javax}/{@code jakarta} reference inside its nested class behind its {@code &&}-guarded
+ * flag, and never widen this class's method descriptors to a servlet type.
+ */
+public final class HttpResponseWrappers {
+
+    private static final boolean IS_JAVAX_STATUS = statusMethodExists("javax.servlet.http.HttpServletResponse");
+    private static final boolean IS_JAKARTA_STATUS = statusMethodExists("jakarta.servlet.http.HttpServletResponse");
+
+    private HttpResponseWrappers() {
+    }
+
+    /**
+     * @return {@code true} when a servlet {@code getStatus()} is available in either namespace.
+     */
+    public static boolean servletStatusSupported() {
+        return IS_JAVAX_STATUS || IS_JAKARTA_STATUS;
+    }
+
+    /**
+     * @param response any object; typically the servlet response captured by a plugin.
+     * @return a wrapper when {@code response} is a javax or jakarta {@code HttpServletResponse} that
+     * exposes {@code getStatus()}, or {@code null} otherwise (e.g. a reactive response), letting the
+     * caller fall through to its own handling.
+     */
+    public static HttpResponseWrapper wrap(Object response) {
+        if (IS_JAVAX_STATUS && response instanceof javax.servlet.http.HttpServletResponse) {
+            return new JavaxHttpServletResponse((javax.servlet.http.HttpServletResponse) response);
+        }
+        if (IS_JAKARTA_STATUS && response instanceof jakarta.servlet.http.HttpServletResponse) {
+            return new JakartaHttpServletResponse((jakarta.servlet.http.HttpServletResponse) response);
+        }
+        return null;
+    }
+
+    private static boolean statusMethodExists(String className) {
+        try {
+            Class<?> clazz = Class.forName(className, false, HttpResponseWrappers.class.getClassLoader());
+            clazz.getMethod("getStatus");
+            return true;
+        } catch (Throwable ignore) {
+            return false;
+        }
+    }
+
+    private static final class JavaxHttpServletResponse implements HttpResponseWrapper {
+        private final javax.servlet.http.HttpServletResponse response;
+
+        private JavaxHttpServletResponse(javax.servlet.http.HttpServletResponse response) {
+            this.response = response;
+        }
+
+        @Override
+        public int getStatus() {
+            return response.getStatus();
+        }
+    }
+
+    private static final class JakartaHttpServletResponse implements HttpResponseWrapper {
+        private final jakarta.servlet.http.HttpServletResponse response;
+
+        private JakartaHttpServletResponse(jakarta.servlet.http.HttpServletResponse response) {
+            this.response = response;
+        }
+
+        @Override
+        public int getStatus() {
+            return response.getStatus();
+        }
+    }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappersTest.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappersTest.java
new file mode 100644
index 0000000000..87cd1a1a91
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpRequestWrappersTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Both javax.servlet-api and jakarta.servlet-api are on this module's test classpath, reproducing the
+ * exact apache/skywalking#13938 condition: both namespaces present at once. These tests assert that
+ * {@link HttpRequestWrappers#wrap(Object)} selects the wrapper matching the live request type rather
+ * than the classpath-presence order that the old exclusive detection got wrong.
+ */
+public class HttpRequestWrappersTest {
+
+    @Test
+    public void wrapJakartaRequest() {
+        jakarta.servlet.http.HttpServletRequest request = mock(jakarta.servlet.http.HttpServletRequest.class);
+        when(request.getHeader("h")).thenReturn("v");
+        when(request.getMethod()).thenReturn("GET");
+        when(request.getRequestURI()).thenReturn("/uri");
+        when(request.getRequestURL()).thenReturn(new StringBuffer("http://localhost/uri"));
+        when(request.getRemoteHost()).thenReturn("remote");
+        when(request.getHeaders("h")).thenReturn(Collections.enumeration(Collections.singletonList("v")));
+
+        HttpRequestWrapper wrapper = HttpRequestWrappers.wrap(request);
+
+        assertTrue(wrapper instanceof HttpRequestWrapper);
+        assertEquals("v", wrapper.getHeader("h"));
+        assertEquals("GET", wrapper.getMethod());
+        assertEquals("/uri", wrapper.getRequestURI());
+        assertEquals("http://localhost/uri", wrapper.getRequestURL().toString());
+        assertEquals("remote", wrapper.getRemoteHost());
+        Enumeration<String> headers = wrapper.getHeaders("h");
+        assertEquals("v", headers.nextElement());
+    }
+
+    @Test
+    public void wrapJavaxRequest() {
+        javax.servlet.http.HttpServletRequest request = mock(javax.servlet.http.HttpServletRequest.class);
+        when(request.getHeader("h")).thenReturn("v");
+        when(request.getMethod()).thenReturn("POST");
+
+        HttpRequestWrapper wrapper = HttpRequestWrappers.wrap(request);
+
+        assertTrue(wrapper instanceof HttpRequestWrapper);
+        assertEquals("v", wrapper.getHeader("h"));
+        assertEquals("POST", wrapper.getMethod());
+    }
+
+    @Test
+    public void wrapNonServletReturnsNull() {
+        assertNull(HttpRequestWrappers.wrap(new Object()));
+        assertNull(HttpRequestWrappers.wrap("not a request"));
+        assertNull(HttpRequestWrappers.wrap(null));
+    }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappersTest.java b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappersTest.java
new file mode 100644
index 0000000000..c470a2c19b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/servlet-commons/src/test/java/org/apache/skywalking/apm/plugin/servlet/HttpResponseWrappersTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.plugin.servlet;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class HttpResponseWrappersTest {
+
+    @Test
+    public void wrapJakartaResponse() {
+        jakarta.servlet.http.HttpServletResponse response = mock(jakarta.servlet.http.HttpServletResponse.class);
+        when(response.getStatus()).thenReturn(503);
+
+        HttpResponseWrapper wrapper = HttpResponseWrappers.wrap(response);
+
+        assertNotNull(wrapper);
+        assertEquals(503, wrapper.getStatus());
+    }
+
+    @Test
+    public void wrapJavaxResponse() {
+        javax.servlet.http.HttpServletResponse response = mock(javax.servlet.http.HttpServletResponse.class);
+        when(response.getStatus()).thenReturn(200);
+
+        HttpResponseWrapper wrapper = HttpResponseWrappers.wrap(response);
+
+        assertNotNull(wrapper);
+        assertEquals(200, wrapper.getStatus());
+    }
+
+    @Test
+    public void servletStatusSupportedWhenApiPresent() {
+        // Both servlet APIs (with getStatus, added in Servlet 3.0) are on the test classpath.
+        assertTrue(HttpResponseWrappers.servletStatusSupported());
+    }
+
+    @Test
+    public void wrapNonServletReturnsNull() {
+        assertNull(HttpResponseWrappers.wrap(new Object()));
+        assertNull(HttpResponseWrappers.wrap(null));
+    }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/pom.xml
index 65c554bb88..07bb6769f1 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/pom.xml
@@ -55,16 +55,24 @@
             <version>5.2.4.RELEASE</version>
             <scope>provided</scope>
         </dependency>
+        <!--
+          The javax/jakarta servlet namespace split for request/response reads is handled by the
+          shared servlet-commons module (JDK-typed HttpRequestWrapper / HttpResponseWrapper).
+          javax.servlet-api is still required at compile time only: GetBeanInterceptor calls
+          spring-web's ServletRequestAttributes.getRequest(), whose return type resolves to
+          javax.servlet.http.HttpServletRequest against the javax-based spring-web here (the value
+          is stored as Object; the live jakarta/javax type is resolved at runtime by the wrappers).
+        -->
         <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>javax.servlet-api</artifactId>
-            <version>${javax-servlet-api.version}</version>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>apm-servlet-commons</artifactId>
+            <version>${project.version}</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>jakarta.servlet</groupId>
-            <artifactId>jakarta.servlet-api</artifactId>
-            <version>6.0.0</version>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>${javax-servlet-api.version}</version>
             <scope>provided</scope>
         </dependency>
     </dependencies>
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrappers.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrappers.java
deleted file mode 100644
index 663ad53c31..0000000000
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrappers.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
-
-import java.util.Enumeration;
-import java.util.Map;
-
-public class HttpServletRequestWrappers {
-
-    public static HttpServletRequestWrapper wrap(jakarta.servlet.http.HttpServletRequest request) {
-        return new JakartaHttpServletRequest(request);
-    }
-
-    public static HttpServletRequestWrapper wrap(javax.servlet.http.HttpServletRequest request) {
-        return new JavaxHttpServletRequest(request);
-    }
-
-    public static class JakartaHttpServletRequest implements HttpServletRequestWrapper {
-
-        private jakarta.servlet.http.HttpServletRequest jakartaRequest;
-
-        public JakartaHttpServletRequest(jakarta.servlet.http.HttpServletRequest jakartaRequest) {
-            this.jakartaRequest = jakartaRequest;
-        }
-
-        @Override
-        public String getHeader(String name) {
-            return jakartaRequest.getHeader(name);
-        }
-
-        @Override
-        public String getMethod() {
-            return jakartaRequest.getMethod();
-        }
-
-        @Override
-        public StringBuffer getRequestURL() {
-            return jakartaRequest.getRequestURL();
-        }
-
-        @Override
-        public String getRemoteHost() {
-            return jakartaRequest.getRemoteHost();
-        }
-
-        @Override
-        public Map<String, String[]> getParameterMap() {
-            return jakartaRequest.getParameterMap();
-        }
-
-        @Override
-        public Enumeration<String> getHeaders(String name) {
-            return jakartaRequest.getHeaders(name);
-        }
-
-    }
-
-    public static class JavaxHttpServletRequest implements HttpServletRequestWrapper {
-        private javax.servlet.http.HttpServletRequest javaxRequest;
-
-        public JavaxHttpServletRequest(javax.servlet.http.HttpServletRequest javaxRequest) {
-            this.javaxRequest = javaxRequest;
-        }
-
-        @Override
-        public String getHeader(String name) {
-            return javaxRequest.getHeader(name);
-        }
-
-        @Override
-        public String getMethod() {
-            return javaxRequest.getMethod();
-        }
-
-        @Override
-        public StringBuffer getRequestURL() {
-            return javaxRequest.getRequestURL();
-        }
-
-        @Override
-        public String getRemoteHost() {
-            return javaxRequest.getRemoteHost();
-        }
-
-        @Override
-        public Map<String, String[]> getParameterMap() {
-            return javaxRequest.getParameterMap();
-        }
-
-        @Override
-        public Enumeration<String> getHeaders(String name) {
-            return javaxRequest.getHeaders(name);
-        }
-
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestUtil.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestUtil.java
index f4f23b1c5b..f6cc0168d8 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestUtil.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestUtil.java
@@ -20,10 +20,10 @@ package org.apache.skywalking.apm.plugin.spring.mvc.commons;
 import org.apache.skywalking.apm.agent.core.context.tag.Tags;
 import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
 import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrapper;
 import org.apache.skywalking.apm.util.StringUtil;
 import org.springframework.http.server.reactive.ServerHttpRequest;
 
-import javax.servlet.http.HttpServletRequest;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -32,27 +32,7 @@ import java.util.List;
 import java.util.Map;
 
 public class RequestUtil {
-    public static void collectHttpParam(HttpServletRequest request, AbstractSpan span) {
-        final Map<String, String[]> parameterMap = request.getParameterMap();
-        if (parameterMap != null && !parameterMap.isEmpty()) {
-            String tagValue = CollectionUtil.toString(parameterMap);
-            tagValue = SpringMVCPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ?
-                    StringUtil.cut(tagValue, SpringMVCPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tagValue;
-            Tags.HTTP.PARAMS.set(span, tagValue);
-        }
-    }
-
-    public static void collectHttpParam(jakarta.servlet.http.HttpServletRequest request, AbstractSpan span) {
-        final Map<String, String[]> parameterMap = request.getParameterMap();
-        if (parameterMap != null && !parameterMap.isEmpty()) {
-            String tagValue = CollectionUtil.toString(parameterMap);
-            tagValue = SpringMVCPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ?
-                    StringUtil.cut(tagValue, SpringMVCPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) : tagValue;
-            Tags.HTTP.PARAMS.set(span, tagValue);
-        }
-    }
-
-    public static void collectHttpParam(HttpServletRequestWrapper request, AbstractSpan span) {
+    public static void collectHttpParam(HttpRequestWrapper request, AbstractSpan span) {
         final Map<String, String[]> parameterMap = request.getParameterMap();
         if (parameterMap != null && !parameterMap.isEmpty()) {
             String tagValue = CollectionUtil.toString(parameterMap);
@@ -75,45 +55,7 @@ public class RequestUtil {
         }
     }
 
-    public static void collectHttpHeaders(HttpServletRequestWrapper request, AbstractSpan span) {
-        final List<String> headersList = new ArrayList<>(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.size());
-        SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.stream()
-                .filter(
-                        headerName -> request.getHeaders(headerName) != null)
-                .forEach(headerName -> {
-                    Enumeration<String> headerValues = request.getHeaders(
-                            headerName);
-                    List<String> valueList = Collections.list(
-                            headerValues);
-                    if (!CollectionUtil.isEmpty(valueList)) {
-                        String headerValue = valueList.toString();
-                        headersList.add(headerName + "=" + headerValue);
-                    }
-                });
-
-        collectHttpHeaders(headersList, span);
-    }
-
-    public static void collectHttpHeaders(HttpServletRequest request, AbstractSpan span) {
-        final List<String> headersList = new ArrayList<>(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.size());
-        SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.stream()
-                .filter(
-                        headerName -> request.getHeaders(headerName) != null)
-                .forEach(headerName -> {
-                    Enumeration<String> headerValues = request.getHeaders(
-                            headerName);
-                    List<String> valueList = Collections.list(
-                            headerValues);
-                    if (!CollectionUtil.isEmpty(valueList)) {
-                        String headerValue = valueList.toString();
-                        headersList.add(headerName + "=" + headerValue);
-                    }
-                });
-
-        collectHttpHeaders(headersList, span);
-    }
-
-    public static void collectHttpHeaders(jakarta.servlet.http.HttpServletRequest request, AbstractSpan span) {
+    public static void collectHttpHeaders(HttpRequestWrapper request, AbstractSpan span) {
         final List<String> headersList = new ArrayList<>(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.size());
         SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS.stream()
                 .filter(
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java
index 67f2709c8f..8f70a71b3c 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/AbstractMethodInterceptor.java
@@ -19,8 +19,6 @@
 package org.apache.skywalking.apm.plugin.spring.mvc.commons.interceptor;
 
 import java.lang.reflect.Method;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.apache.skywalking.apm.agent.core.context.CarrierItem;
 import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
 import org.apache.skywalking.apm.agent.core.context.ContextManager;
@@ -36,9 +34,11 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInt
 import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
 import org.apache.skywalking.apm.agent.core.util.MethodUtil;
 import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrapper;
+import org.apache.skywalking.apm.plugin.servlet.HttpRequestWrappers;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrapper;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrappers;
 import org.apache.skywalking.apm.plugin.spring.mvc.commons.EnhanceRequireObjectCache;
-import org.apache.skywalking.apm.plugin.spring.mvc.commons.HttpServletRequestWrapper;
-import org.apache.skywalking.apm.plugin.spring.mvc.commons.HttpServletRequestWrappers;
 import org.apache.skywalking.apm.plugin.spring.mvc.commons.RequestUtil;
 import org.apache.skywalking.apm.plugin.spring.mvc.commons.SpringMVCPluginConfig;
 import org.apache.skywalking.apm.plugin.spring.mvc.commons.exception.IllegalMethodStackDepthException;
@@ -57,40 +57,6 @@ import static org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESP
  */
 public abstract class AbstractMethodInterceptor implements InstanceMethodsAroundInterceptor {
     private static final ILog LOGGER = LogManager.getLogger(AbstractMethodInterceptor.class);
-    private static boolean IS_SERVLET_GET_STATUS_METHOD_EXIST;
-    private static boolean IS_JAKARTA_SERVLET_GET_STATUS_METHOD_EXIST;
-    private static final String SERVLET_RESPONSE_CLASS = "javax.servlet.http.HttpServletResponse";
-    private static final String JAKARTA_SERVLET_RESPONSE_CLASS = "jakarta.servlet.http.HttpServletResponse";
-    private static final String GET_STATUS_METHOD = "getStatus";
-
-    private static boolean IN_SERVLET_CONTAINER;
-    private static boolean IS_JAVAX = false;
-    private static boolean IS_JAKARTA = false;
-
-    static {
-        IS_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(
-            AbstractMethodInterceptor.class.getClassLoader(), SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD);
-        IS_JAKARTA_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(
-            AbstractMethodInterceptor.class.getClassLoader(),
-            JAKARTA_SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD
-        );
-        // Check both javax and jakarta independently — both may exist on the classpath.
-        // For example, a Spring MVC 6.x (Jakarta) app may have javax.servlet as a
-        // transitive dependency. The runtime request type determines which path is used.
-        try {
-            Class.forName(SERVLET_RESPONSE_CLASS, true, AbstractMethodInterceptor.class.getClassLoader());
-            IS_JAVAX = true;
-            IN_SERVLET_CONTAINER = true;
-        } catch (Exception ignore) {
-        }
-        try {
-            Class.forName(
-                JAKARTA_SERVLET_RESPONSE_CLASS, true, AbstractMethodInterceptor.class.getClassLoader());
-            IS_JAKARTA = true;
-            IN_SERVLET_CONTAINER = true;
-        } catch (Exception ignore) {
-        }
-    }
 
     public abstract String getRequestURL(Method method);
 
@@ -115,16 +81,9 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
             if (stackDepth == null) {
                 final ContextCarrier contextCarrier = new ContextCarrier();
 
-                if (IN_SERVLET_CONTAINER && IS_JAVAX && HttpServletRequest.class.isAssignableFrom(request.getClass())) {
-                    final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
-                    handleBeforeMethod(
-                        objInst, method, HttpServletRequestWrappers.wrap(httpServletRequest), contextCarrier);
-
-                } else if (IN_SERVLET_CONTAINER && IS_JAKARTA && jakarta.servlet.http.HttpServletRequest.class.isAssignableFrom(
-                    request.getClass())) {
-                    final jakarta.servlet.http.HttpServletRequest httpServletRequest = (jakarta.servlet.http.HttpServletRequest) request;
-                    handleBeforeMethod(
-                        objInst, method, HttpServletRequestWrappers.wrap(httpServletRequest), contextCarrier);
+                final HttpRequestWrapper httpServletRequest = HttpRequestWrappers.wrap(request);
+                if (httpServletRequest != null) {
+                    handleBeforeMethod(objInst, method, httpServletRequest, contextCarrier);
 
                 } else if (ServerHttpRequest.class.isAssignableFrom(request.getClass())) {
                     final ServerHttpRequest serverHttpRequest = (ServerHttpRequest) request;
@@ -167,7 +126,7 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
     }
 
     private void handleBeforeMethod(EnhancedInstance objInst, Method method,
-                                    HttpServletRequestWrapper httpServletRequest, ContextCarrier contextCarrier) {
+                                    HttpRequestWrapper httpServletRequest, ContextCarrier contextCarrier) {
         CarrierItem next = contextCarrier.items();
         while (next.hasNext()) {
             next = next.next();
@@ -225,14 +184,11 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
 
                     Integer statusCode = null;
 
-                    if (IS_SERVLET_GET_STATUS_METHOD_EXIST && HttpServletResponse.class.isAssignableFrom(
-                        response.getClass())) {
-                        statusCode = ((HttpServletResponse) response).getStatus();
-                    } else if (IS_JAKARTA_SERVLET_GET_STATUS_METHOD_EXIST && jakarta.servlet.http.HttpServletResponse.class.isAssignableFrom(
-                        response.getClass())) {
-                        statusCode = ((jakarta.servlet.http.HttpServletResponse) response).getStatus();
+                    final HttpResponseWrapper httpServletResponse = HttpResponseWrappers.wrap(response);
+                    if (httpServletResponse != null) {
+                        statusCode = httpServletResponse.getStatus();
                     } else if (ServerHttpResponse.class.isAssignableFrom(response.getClass())) {
-                        if (IS_SERVLET_GET_STATUS_METHOD_EXIST || IS_JAKARTA_SERVLET_GET_STATUS_METHOD_EXIST) {
+                        if (HttpResponseWrappers.servletStatusSupported()) {
                             statusCode = ((ServerHttpResponse) response).getRawStatusCode();
                         }
                         Object context = runtimeContext.get(REACTIVE_ASYNC_SPAN_IN_RUNTIME_CONTEXT);
@@ -256,11 +212,9 @@ public abstract class AbstractMethodInterceptor implements InstanceMethodsAround
 
                 // Active HTTP parameter collection automatically in the profiling context.
                 if (!SpringMVCPluginConfig.Plugin.SpringMVC.COLLECT_HTTP_PARAMS && span.isProfiling()) {
-                    if (IS_JAVAX && HttpServletRequest.class.isAssignableFrom(request.getClass())) {
-                        RequestUtil.collectHttpParam((HttpServletRequest) request, span);
-                    } else if (IS_JAKARTA && jakarta.servlet.http.HttpServletRequest.class.isAssignableFrom(
-                        request.getClass())) {
-                        RequestUtil.collectHttpParam((jakarta.servlet.http.HttpServletRequest) request, span);
+                    final HttpRequestWrapper httpServletRequest = HttpRequestWrappers.wrap(request);
+                    if (httpServletRequest != null) {
+                        RequestUtil.collectHttpParam(httpServletRequest, span);
                     } else if (ServerHttpRequest.class.isAssignableFrom(request.getClass())) {
                         RequestUtil.collectHttpParam((ServerHttpRequest) request, span);
                     }
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/define/ApplicationDispatcherInstrumentation.java b/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/define/ApplicationDispatcherInstrumentation.java
deleted file mode 100644
index 048ee28f38..0000000000
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/define/ApplicationDispatcherInstrumentation.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.plugin.tomcat10x.define;
-
-import net.bytebuddy.description.method.MethodDescription;
-import net.bytebuddy.matcher.ElementMatcher;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
-import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
-
-import static net.bytebuddy.matcher.ElementMatchers.any;
-import static net.bytebuddy.matcher.ElementMatchers.named;
-import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
-
-public class ApplicationDispatcherInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
-
-    private static final String ENHANCE_CLASS = "org.apache.catalina.core.ApplicationDispatcher";
-    private static final String ENHANCE_METHOD = "forward";
-    public static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.tomcat10x.ForwardInterceptor";
-
-    @Override
-    protected String[] witnessClasses() {
-        return new String[]{"jakarta.servlet.http.HttpServletResponse"};
-    }
-
-    @Override
-    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
-        return new ConstructorInterceptPoint[] {
-            new ConstructorInterceptPoint() {
-                @Override
-                public ElementMatcher<MethodDescription> getConstructorMatcher() {
-                    return any();
-                }
-
-                @Override
-                public String getConstructorInterceptor() {
-                    return INTERCEPTOR_CLASS;
-                }
-            }
-        };
-    }
-
-    @Override
-    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
-        return new InstanceMethodsInterceptPoint[] {
-            new InstanceMethodsInterceptPoint() {
-                @Override
-                public ElementMatcher<MethodDescription> getMethodsMatcher() {
-                    return named(ENHANCE_METHOD);
-                }
-
-                @Override
-                public String getMethodsInterceptor() {
-                    return INTERCEPTOR_CLASS;
-                }
-
-                @Override
-                public boolean isOverrideArgs() {
-                    return false;
-                }
-            }
-        };
-    }
-
-    @Override
-    protected ClassMatch enhanceClass() {
-        return byName(ENHANCE_CLASS);
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/define/TomcatInstrumentation.java b/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/define/TomcatInstrumentation.java
deleted file mode 100644
index 0ba3356a1d..0000000000
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/define/TomcatInstrumentation.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.plugin.tomcat10x.define;
-
-import net.bytebuddy.description.method.MethodDescription;
-import net.bytebuddy.matcher.ElementMatcher;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
-import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
-
-import static net.bytebuddy.matcher.ElementMatchers.named;
-import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
-
-public class TomcatInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
-
-    /**
-     * Enhance class.
-     */
-    private static final String ENHANCE_CLASS = "org.apache.catalina.core.StandardHostValve";
-
-    /**
-     * The intercept class for "invoke" method in the class "org.apache.catalina.core.StandardHostValve"
-     */
-    private static final String INVOKE_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.tomcat10x.TomcatInvokeInterceptor";
-
-    /**
-     * The intercept class for "exception" method in the class "org.apache.catalina.core.StandardHostValve"
-     */
-    private static final String EXCEPTION_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.tomcat10x.TomcatExceptionInterceptor";
-
-    @Override
-    protected String[] witnessClasses() {
-        return new String[]{"jakarta.servlet.http.HttpServletResponse"};
-    }
-
-    @Override
-    protected ClassMatch enhanceClass() {
-        return byName(ENHANCE_CLASS);
-    }
-
-    @Override
-    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
-        return null;
-    }
-
-    @Override
-    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
-        return new InstanceMethodsInterceptPoint[] {
-            new InstanceMethodsInterceptPoint() {
-                @Override
-                public ElementMatcher<MethodDescription> getMethodsMatcher() {
-                    return named("invoke");
-                }
-
-                @Override
-                public String getMethodsInterceptor() {
-                    return INVOKE_INTERCEPT_CLASS;
-                }
-
-                @Override
-                public boolean isOverrideArgs() {
-                    return false;
-                }
-            },
-            new InstanceMethodsInterceptPoint() {
-                @Override
-                public ElementMatcher<MethodDescription> getMethodsMatcher() {
-                    return named("throwable");
-                }
-
-                @Override
-                public String getMethodsInterceptor() {
-                    return EXCEPTION_INTERCEPT_CLASS;
-                }
-
-                @Override
-                public boolean isOverrideArgs() {
-                    return false;
-                }
-            }
-        };
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/ForwardInterceptor.java b/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/ForwardInterceptor.java
deleted file mode 100644
index ab43e22fb3..0000000000
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/ForwardInterceptor.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- *
- */
-
-package org.apache.skywalking.apm.plugin.tomcat78x;
-
-import java.lang.reflect.Method;
-import java.util.HashMap;
-import java.util.Map;
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
-import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceConstructorInterceptor;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
-
-public class ForwardInterceptor implements InstanceMethodsAroundInterceptor, InstanceConstructorInterceptor {
-
-    @Override
-    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-        MethodInterceptResult result) throws Throwable {
-        if (ContextManager.isActive()) {
-            AbstractSpan abstractTracingSpan = ContextManager.activeSpan();
-            Map<String, String> eventMap = new HashMap<String, String>();
-            eventMap.put("forward-url", objInst.getSkyWalkingDynamicField() == null ? "" : String.valueOf(objInst.getSkyWalkingDynamicField()));
-            abstractTracingSpan.log(System.currentTimeMillis(), eventMap);
-            ContextManager.getRuntimeContext().put(Constants.FORWARD_REQUEST_FLAG, true);
-        }
-    }
-
-    @Override
-    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-        Object ret) throws Throwable {
-        ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG);
-        return ret;
-    }
-
-    @Override
-    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
-        Class<?>[] argumentsTypes, Throwable t) {
-
-    }
-
-    @Override
-    public void onConstruct(EnhancedInstance objInst, Object[] allArguments) {
-        objInst.setSkyWalkingDynamicField(allArguments[1]);
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatExceptionInterceptor.java b/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatExceptionInterceptor.java
deleted file mode 100644
index 28c8a9a20a..0000000000
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatExceptionInterceptor.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.plugin.tomcat78x;
-
-import java.lang.reflect.Method;
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
-
-public class TomcatExceptionInterceptor implements InstanceMethodsAroundInterceptor {
-    @Override
-    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-        MethodInterceptResult result) throws Throwable {
-        ContextManager.activeSpan().log((Throwable) allArguments[2]);
-    }
-
-    @Override
-    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-        Object ret) throws Throwable {
-        return ret;
-    }
-
-    @Override
-    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
-        Class<?>[] argumentsTypes, Throwable t) {
-
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java b/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java
deleted file mode 100644
index 29004e6e46..0000000000
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptor.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.plugin.tomcat78x;
-
-import java.lang.reflect.Method;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Map;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.catalina.connector.Request;
-import org.apache.skywalking.apm.agent.core.context.CarrierItem;
-import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
-import org.apache.skywalking.apm.agent.core.context.ContextManager;
-import org.apache.skywalking.apm.agent.core.context.tag.Tags;
-import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
-import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
-import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
-import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
-import org.apache.skywalking.apm.agent.core.util.MethodUtil;
-import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
-import org.apache.skywalking.apm.util.StringUtil;
-import org.apache.tomcat.util.http.Parameters;
-
-/**
- * {@link TomcatInvokeInterceptor} fetch the serialized context data by using {@link
- * HttpServletRequest#getHeader(String)}. The {@link TraceSegment#ref} of current trace segment will reference to the
- * trace segment id of the previous level if the serialized context is not null.
- */
-public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor {
-
-    private static boolean IS_SERVLET_GET_STATUS_METHOD_EXIST;
-    private static final String SERVLET_RESPONSE_CLASS = "javax.servlet.http.HttpServletResponse";
-    private static final String GET_STATUS_METHOD = "getStatus";
-
-    static {
-        IS_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(
-            TomcatInvokeInterceptor.class.getClassLoader(), SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD);
-    }
-
-    /**
-     * * The {@link TraceSegment#ref} of current trace segment will reference to the trace segment id of the previous
-     * level if the serialized context is not null.
-     *
-     * @param result change this result, if you want to truncate the method.
-     */
-    @Override
-    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-                             MethodInterceptResult result) throws Throwable {
-        Request request = (Request) allArguments[0];
-        ContextCarrier contextCarrier = new ContextCarrier();
-
-        CarrierItem next = contextCarrier.items();
-        while (next.hasNext()) {
-            next = next.next();
-            next.setHeadValue(request.getHeader(next.getHeadKey()));
-        }
-        String operationName =  String.join(":", request.getMethod(), request.getRequestURI());
-        AbstractSpan span = ContextManager.createEntrySpan(operationName, contextCarrier);
-        Tags.URL.set(span, request.getRequestURL().toString());
-        Tags.HTTP.METHOD.set(span, request.getMethod());
-        span.setComponent(ComponentsDefine.TOMCAT);
-        SpanLayer.asHttp(span);
-
-        if (TomcatPluginConfig.Plugin.Tomcat.COLLECT_HTTP_PARAMS) {
-            collectHttpParam(request, span);
-        }
-    }
-
-    @Override
-    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
-                              Object ret) throws Throwable {
-        Request request = (Request) allArguments[0];
-        HttpServletResponse response = (HttpServletResponse) allArguments[1];
-
-        AbstractSpan span = ContextManager.activeSpan();
-        if (IS_SERVLET_GET_STATUS_METHOD_EXIST) {
-            Tags.HTTP_RESPONSE_STATUS_CODE.set(span, response.getStatus());
-            if (response.getStatus() >= 400) {
-                span.errorOccurred();
-            }
-        }
-        // Active HTTP parameter collection automatically in the profiling context.
-        if (!TomcatPluginConfig.Plugin.Tomcat.COLLECT_HTTP_PARAMS && span.isProfiling()) {
-            collectHttpParam(request, span);
-        }
-        ContextManager.getRuntimeContext().remove(Constants.FORWARD_REQUEST_FLAG);
-        ContextManager.stopSpan();
-        return ret;
-    }
-
-    @Override
-    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
-                                      Class<?>[] argumentsTypes, Throwable t) {
-        AbstractSpan span = ContextManager.activeSpan();
-        span.log(t);
-    }
-
-    private void collectHttpParam(Request request, AbstractSpan span) {
-        final Map<String, String[]> parameterMap = new HashMap<>();
-        final org.apache.coyote.Request coyoteRequest = request.getCoyoteRequest();
-        final Parameters parameters = coyoteRequest.getParameters();
-        for (final Enumeration<String> names = parameters.getParameterNames(); names.hasMoreElements(); ) {
-            final String name = names.nextElement();
-            parameterMap.put(name, parameters.getParameterValues(name));
-        }
-
-        if (!parameterMap.isEmpty()) {
-            String tagValue = CollectionUtil.toString(parameterMap);
-            tagValue = TomcatPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD > 0 ?
-                StringUtil.cut(tagValue, TomcatPluginConfig.Plugin.Http.HTTP_PARAMS_LENGTH_THRESHOLD) :
-                tagValue;
-            Tags.HTTP.PARAMS.set(span, tagValue);
-        }
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatPluginConfig.java b/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatPluginConfig.java
deleted file mode 100644
index 4bc6174d73..0000000000
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatPluginConfig.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package org.apache.skywalking.apm.plugin.tomcat78x;
-
-import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
-
-public class TomcatPluginConfig {
-    public static class Plugin {
-        @PluginConfig(root = TomcatPluginConfig.class)
-        public static class Tomcat {
-            /**
-             * This config item controls that whether the Tomcat plugin should collect the parameters of the request.
-             */
-            public static boolean COLLECT_HTTP_PARAMS = false;
-        }
-
-        @PluginConfig(root = TomcatPluginConfig.class)
-        public static class Http {
-            /**
-             * When either {@link Tomcat#COLLECT_HTTP_PARAMS} is enabled, how many characters to keep and send to the
-             * OAP backend, use negative values to keep and send the complete parameters, NB. this config item is added
-             * for the sake of performance
-             */
-            public static int HTTP_PARAMS_LENGTH_THRESHOLD = 1024;
-        }
-    }
-}
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/pom.xml
similarity index 64%
copy from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
copy to apm-sniffer/apm-sdk-plugin/tomcat-plugin/pom.xml
index 7c54849e28..d0b23363e1 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/pom.xml
@@ -25,8 +25,18 @@
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>tomcat-10x-plugin</artifactId>
+    <artifactId>apm-tomcat-plugin</artifactId>
 
+    <name>tomcat-plugin</name>
+
+    <!--
+      Unified Tomcat plugin covering Tomcat 7/8/9 (javax.servlet) and Tomcat 10+ (jakarta.servlet).
+      The interceptor reads the request through Catalina-native org.apache.catalina.connector.Request
+      (namespace-neutral) and the response status through the shared servlet-commons wrapper, so a
+      single plugin activates on any Tomcat via the Catalina StandardHostValve match — no per-namespace
+      witness or duplicate module needed. Compiled against a jakarta-era tomcat-embed-core; the Catalina
+      class/method names used are stable across the supported Tomcat range.
+    -->
     <properties>
         <tomcat.version>10.0.22</tomcat.version>
     </properties>
@@ -37,6 +47,12 @@
             <version>${tomcat.version}</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.skywalking</groupId>
+            <artifactId>apm-servlet-commons</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
 </project>
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/Constants.java b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/Constants.java
similarity index 94%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/Constants.java
rename to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/Constants.java
index 64501083e1..9f783d15c0 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/Constants.java
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/Constants.java
@@ -17,7 +17,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.tomcat78x;
+package org.apache.skywalking.apm.plugin.tomcat;
 
 public class Constants {
     public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/ForwardInterceptor.java b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/ForwardInterceptor.java
similarity index 98%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/ForwardInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/ForwardInterceptor.java
index 8c64a1d0a9..6f48059390 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/ForwardInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/ForwardInterceptor.java
@@ -17,7 +17,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.tomcat10x;
+package org.apache.skywalking.apm.plugin.tomcat;
 
 import org.apache.skywalking.apm.agent.core.context.ContextManager;
 import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/TomcatExceptionInterceptor.java b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatExceptionInterceptor.java
similarity index 97%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/TomcatExceptionInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatExceptionInterceptor.java
index ac9ba9f61e..ab854aa554 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/TomcatExceptionInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatExceptionInterceptor.java
@@ -16,7 +16,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.tomcat10x;
+package org.apache.skywalking.apm.plugin.tomcat;
 
 import org.apache.skywalking.apm.agent.core.context.ContextManager;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/TomcatInvokeInterceptor.java b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptor.java
similarity index 87%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/TomcatInvokeInterceptor.java
rename to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptor.java
index 52bedf994d..9cb009199a 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/TomcatInvokeInterceptor.java
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptor.java
@@ -16,9 +16,8 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.tomcat10x;
+package org.apache.skywalking.apm.plugin.tomcat;
 
-import jakarta.servlet.http.HttpServletResponse;
 import org.apache.catalina.connector.Request;
 import org.apache.skywalking.apm.agent.core.context.CarrierItem;
 import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
@@ -32,6 +31,8 @@ import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceM
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
 import org.apache.skywalking.apm.agent.core.util.CollectionUtil;
 import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrapper;
+import org.apache.skywalking.apm.plugin.servlet.HttpResponseWrappers;
 import org.apache.skywalking.apm.util.StringUtil;
 import org.apache.tomcat.util.http.Parameters;
 
@@ -42,9 +43,6 @@ import java.util.Map;
 
 public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor {
 
-    private static final String SERVLET_RESPONSE_CLASS = "jakarta.servlet.http.HttpServletResponse";
-    private static final String GET_STATUS_METHOD = "getStatus";
-
     @Override
     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                              MethodInterceptResult result) throws Throwable {
@@ -72,12 +70,17 @@ public class TomcatInvokeInterceptor implements InstanceMethodsAroundInterceptor
     public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes,
                               Object ret) throws Throwable {
         Request request = (Request) allArguments[0];
-        HttpServletResponse response = (HttpServletResponse) allArguments[1];
 
         AbstractSpan span = ContextManager.activeSpan();
-        Tags.HTTP_RESPONSE_STATUS_CODE.set(span, response.getStatus());
-        if (response.getStatus() >= 400) {
-            span.errorOccurred();
+        // The response status is read through the namespace-agnostic wrapper; it returns null when
+        // getStatus() is unavailable (pre-Servlet-3.0), preserving the historical guard behavior.
+        HttpResponseWrapper response = HttpResponseWrappers.wrap(allArguments[1]);
+        if (response != null) {
+            int statusCode = response.getStatus();
+            Tags.HTTP_RESPONSE_STATUS_CODE.set(span, statusCode);
+            if (statusCode >= 400) {
+                span.errorOccurred();
+            }
         }
         // Active HTTP parameter collection automatically in the profiling context.
         if (!TomcatPluginConfig.Plugin.Tomcat.COLLECT_HTTP_PARAMS && span.isProfiling()) {
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/TomcatPluginConfig.java b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatPluginConfig.java
similarity index 97%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/TomcatPluginConfig.java
rename to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatPluginConfig.java
index 2c2865d63a..0a1d713cf9 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat10x/TomcatPluginConfig.java
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/TomcatPluginConfig.java
@@ -16,7 +16,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.tomcat10x;
+package org.apache.skywalking.apm.plugin.tomcat;
 
 import org.apache.skywalking.apm.agent.core.boot.PluginConfig;
 
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/define/ApplicationDispatcherInstrumentation.java b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/define/ApplicationDispatcherInstrumentation.java
similarity index 92%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/define/ApplicationDispatcherInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/define/ApplicationDispatcherInstrumentation.java
index 14158594fa..f1d8f0370d 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/define/ApplicationDispatcherInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/define/ApplicationDispatcherInstrumentation.java
@@ -16,7 +16,7 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.tomcat78x.define;
+package org.apache.skywalking.apm.plugin.tomcat.define;
 
 import net.bytebuddy.description.method.MethodDescription;
 import net.bytebuddy.matcher.ElementMatcher;
@@ -33,12 +33,7 @@ public class ApplicationDispatcherInstrumentation extends ClassInstanceMethodsEn
 
     private static final String ENHANCE_CLASS = "org.apache.catalina.core.ApplicationDispatcher";
     private static final String ENHANCE_METHOD = "forward";
-    public static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.tomcat78x.ForwardInterceptor";
-
-    @Override
-    protected String[] witnessClasses() {
-        return new String[]{"javax.servlet.http.HttpServletResponse"};
-    }
+    public static final String INTERCEPTOR_CLASS = "org.apache.skywalking.apm.plugin.tomcat.ForwardInterceptor";
 
     @Override
     public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/define/TomcatInstrumentation.java b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/define/TomcatInstrumentation.java
similarity index 91%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/define/TomcatInstrumentation.java
rename to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/define/TomcatInstrumentation.java
index ffcae42fe8..67e9a4296d 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat78x/define/TomcatInstrumentation.java
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/java/org/apache/skywalking/apm/plugin/tomcat/define/TomcatInstrumentation.java
@@ -16,13 +16,13 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.tomcat78x.define;
+package org.apache.skywalking.apm.plugin.tomcat.define;
 
 import net.bytebuddy.description.method.MethodDescription;
 import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
 import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
-import org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
 import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
 
 import static net.bytebuddy.matcher.ElementMatchers.named;
@@ -38,17 +38,12 @@ public class TomcatInstrumentation extends ClassInstanceMethodsEnhancePluginDefi
     /**
      * The intercept class for "invoke" method in the class "org.apache.catalina.core.StandardHostValve"
      */
-    private static final String INVOKE_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.tomcat78x.TomcatInvokeInterceptor";
+    private static final String INVOKE_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.tomcat.TomcatInvokeInterceptor";
 
     /**
      * The intercept class for "exception" method in the class "org.apache.catalina.core.StandardHostValve"
      */
-    private static final String EXCEPTION_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.tomcat78x.TomcatExceptionInterceptor";
-
-    @Override
-    protected String[] witnessClasses() {
-        return new String[]{"javax.servlet.http.HttpServletResponse"};
-    }
+    private static final String EXCEPTION_INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.tomcat.TomcatExceptionInterceptor";
 
     @Override
     protected ClassMatch enhanceClass() {
diff --git a/test/plugin/scenarios/spring-6.x-scenario/support-version.list b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/resources/skywalking-plugin.def
similarity index 82%
copy from test/plugin/scenarios/spring-6.x-scenario/support-version.list
copy to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/resources/skywalking-plugin.def
index c96f0b4304..35eb529458 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/support-version.list
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/main/resources/skywalking-plugin.def
@@ -14,6 +14,5 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-6.0.4
-6.1.0
-6.1.1
+tomcat=org.apache.skywalking.apm.plugin.tomcat.define.TomcatInstrumentation
+tomcat=org.apache.skywalking.apm.plugin.tomcat.define.ApplicationDispatcherInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/test/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptorTest.java
similarity index 90%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptorTest.java
rename to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/test/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptorTest.java
index 4aeb68c89a..b3fe9b9022 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/tomcat78x/TomcatInvokeInterceptorTest.java
+++ b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/test/java/org/apache/skywalking/apm/plugin/tomcat/TomcatInvokeInterceptorTest.java
@@ -16,15 +16,15 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.tomcat78x;
+package org.apache.skywalking.apm.plugin.tomcat;
 
 import static org.apache.skywalking.apm.agent.test.tools.SpanAssert.assertComponent;
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.mockito.Mockito.when;
 import java.util.List;
-import javax.servlet.http.HttpServletResponse;
 import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
 import org.apache.skywalking.apm.agent.core.context.SW8CarrierItem;
 import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
 import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity;
@@ -65,8 +65,14 @@ public class TomcatInvokeInterceptorTest {
 
     @Mock
     private Request request;
+    /**
+     * The merged tomcat-plugin compiles against tomcat-embed-core 10.0.22, whose Catalina
+     * {@link Response} implements {@code jakarta.servlet.http.HttpServletResponse}. The interceptor
+     * reads the status through {@code HttpResponseWrappers.wrap(response).getStatus()}, which selects
+     * the jakarta branch for this mock and returns the stubbed status below.
+     */
     @Mock
-    private HttpServletResponse response;
+    private Response response;
     @Mock
     private MethodInterceptResult methodInterceptResult;
 
@@ -177,6 +183,10 @@ public class TomcatInvokeInterceptorTest {
         assertThat(span.getOperationName(), is("GET:/test/testRequestURL"));
         assertComponent(span, ComponentsDefine.TOMCAT);
         SpanAssert.assertTag(span, 0, "http://localhost:8080/test/testRequestURL");
+        // The status read via HttpResponseWrappers.wrap(response).getStatus() is recorded as the
+        // http.status_code tag; the original tomcat78x test omitted this assertion.
+        assertThat(SpanHelper.getTags(span).get(2).getKey().key(), is("http.status_code"));
+        SpanAssert.assertTag(span, 2, "200");
         assertThat(span.isEntry(), is(true));
         SpanAssert.assertLayer(span, SpanLayer.HTTP);
     }
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
similarity index 100%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
rename to apm-sniffer/apm-sdk-plugin/tomcat-plugin/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
diff --git a/docs/en/setup/service-agent/java-agent/Java-Plugin-Development-Guide.md b/docs/en/setup/service-agent/java-agent/Java-Plugin-Development-Guide.md
index 201835a1dc..c581000ea5 100644
--- a/docs/en/setup/service-agent/java-agent/Java-Plugin-Development-Guide.md
+++ b/docs/en/setup/service-agent/java-agent/Java-Plugin-Development-Guide.md
@@ -360,7 +360,7 @@ The following sections will tell you how to implement the interceptor.
 
 3. Add plugin definition into the `skywalking-plugin.def` file.
 ```properties
-tomcat-7.x/8.x=TomcatInstrumentation
+tomcat=TomcatInstrumentation
 ```
 
 4. Set up `witnessClasses` and/or `witnessMethods` if the instrumentation has to be activated in specific versions.
diff --git a/docs/en/setup/service-agent/java-agent/Plugin-list.md b/docs/en/setup/service-agent/java-agent/Plugin-list.md
index ed16dc1f85..2e5ad78336 100644
--- a/docs/en/setup/service-agent/java-agent/Plugin-list.md
+++ b/docs/en/setup/service-agent/java-agent/Plugin-list.md
@@ -55,7 +55,7 @@
 - jedis-4.x
 - jetty-client-9.0
 - jetty-client-9.x
-- jetty-server-9.x
+- jetty-server
 - kafka-0.11.x/1.x/2.x
 - kafka-3.7.x
 - kafka-3.9.x
@@ -133,8 +133,7 @@
 - spymemcached-2.x
 - struts2-2.x
 - thrift
-- tomcat-7.x/8.x
-- tomcat-10.x
+- tomcat
 - toolkit-counter
 - toolkit-gauge
 - toolkit-histogram
@@ -180,7 +179,6 @@
 - jersey-3.x
 - grizzly-2.3.x-4.x
 - grizzly-2.3.x-4.x-threadpool
-- jetty-server-11.x
 - jetty-client-11.x
 - websphere-liberty-23.x
 - spring-cloud-gateway-4.x
diff --git a/test/plugin/scenarios/jersey-3.x-scenario/support-version.list b/test/plugin/scenarios/jersey-3.x-scenario/support-version.list
index bf93530913..ac6d65588a 100644
--- a/test/plugin/scenarios/jersey-3.x-scenario/support-version.list
+++ b/test/plugin/scenarios/jersey-3.x-scenario/support-version.list
@@ -15,4 +15,4 @@
 # limitations under the License.
 
 3.0.0
-3.1.1
+3.1.12
diff --git a/test/plugin/scenarios/jetty-11.x-scenario/support-version.list b/test/plugin/scenarios/jetty-11.x-scenario/support-version.list
index 140bec1629..ad7671ecf9 100644
--- a/test/plugin/scenarios/jetty-11.x-scenario/support-version.list
+++ b/test/plugin/scenarios/jetty-11.x-scenario/support-version.list
@@ -14,6 +14,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-11.0.0
-11.0.7
-11.0.15
+11.0.26
diff --git a/test/plugin/scenarios/resteasy-6.x-scenario/support-version.list b/test/plugin/scenarios/resteasy-6.x-scenario/support-version.list
index 49ada0d6d6..9b953ddf82 100644
--- a/test/plugin/scenarios/resteasy-6.x-scenario/support-version.list
+++ b/test/plugin/scenarios/resteasy-6.x-scenario/support-version.list
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # test all 6.x version, with corresponding latest patch version
-6.2.4.Final
+6.2.16.Final
 6.1.0.Final
 6.0.3.Final
\ No newline at end of file
diff --git a/test/plugin/scenarios/resttemplate-6.x-scenario/bin/startup.sh b/test/plugin/scenarios/resttemplate-6.x-scenario/bin/startup.sh
index 197feca45a..bd736d21e8 100644
--- a/test/plugin/scenarios/resttemplate-6.x-scenario/bin/startup.sh
+++ b/test/plugin/scenarios/resttemplate-6.x-scenario/bin/startup.sh
@@ -18,6 +18,6 @@
 
 home="$(cd "$(dirname $0)"; pwd)"
 
-export SW_EXCLUDE_PLUGINS=spring-mvc-annotation,spring-mvc-annotation-3.x,spring-mvc-annotation-4.x,spring-mvc-annotation-5.x,spring-resttemplate-4.x,tomcat-7.x/8.x,tomcat-10.x
+export SW_EXCLUDE_PLUGINS=spring-mvc-annotation,spring-mvc-annotation-3.x,spring-mvc-annotation-4.x,spring-mvc-annotation-5.x,spring-resttemplate-4.x,tomcat
 
 java -jar ${agent_opts} ${home}/../libs/resttemplate-6.x-scenario.jar &
diff --git a/test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml
index 926a3f2b4c..081211529f 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml
+++ b/test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml
@@ -371,5 +371,9 @@ segmentItems:
       tags:
       - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/case/resttemplate'}
       - {key: http.method, value: GET}
+      - key: http.params
+        value: |-
+          q1=[v1]
+          chinese=[中文]
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
diff --git a/test/plugin/scenarios/spring-6.x-scenario/configuration.yml b/test/plugin/scenarios/spring-6.x-scenario/configuration.yml
index 4e81ad6a99..bb658f8656 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/configuration.yml
+++ b/test/plugin/scenarios/spring-6.x-scenario/configuration.yml
@@ -15,9 +15,9 @@
 # limitations under the License.
 
 type: tomcat
-entryService: http://localhost:8080/spring-6.x-scenario/case/resttemplate
+entryService: '"http://localhost:8080/spring-6.x-scenario/case/resttemplate?q1=v1&chinese=%e4%b8%ad%e6%96%87"'
 healthCheck: http://localhost:8080/spring-6.x-scenario/healthCheck
 runningMode: with_optional
 withPlugins: apm-spring-annotation-plugin-*.jar;apm-*-6.x-plugin-*.jar
 environment:
-  - CATALINA_OPTS="-Dskywalking.plugin.http.include_http_headers=mock_header"
+  - CATALINA_OPTS="-Dskywalking.plugin.http.include_http_headers=mock_header -Dskywalking.plugin.springmvc.collect_http_params=true"
diff --git a/test/plugin/scenarios/spring-6.x-scenario/support-version.list b/test/plugin/scenarios/spring-6.x-scenario/support-version.list
index c96f0b4304..947a86b2f5 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/support-version.list
+++ b/test/plugin/scenarios/spring-6.x-scenario/support-version.list
@@ -15,5 +15,5 @@
 # limitations under the License.
 
 6.0.4
-6.1.0
 6.1.1
+6.2.19
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/resources/skywalking-plugin.def b/test/plugin/scenarios/spring-boot-2.x-scenario/bin/startup.sh
similarity index 77%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/resources/skywalking-plugin.def
rename to test/plugin/scenarios/spring-boot-2.x-scenario/bin/startup.sh
index baa002ba28..cc7c8bd115 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/src/main/resources/skywalking-plugin.def
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/bin/startup.sh
@@ -1,3 +1,5 @@
+#!/bin/bash
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,5 +16,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-tomcat-10.x=org.apache.skywalking.apm.plugin.tomcat10x.define.TomcatInstrumentation
-tomcat-10.x=org.apache.skywalking.apm.plugin.tomcat10x.define.ApplicationDispatcherInstrumentation
+home="$(cd "$(dirname $0)"; pwd)"
+
+java -Dskywalking.plugin.http.include_http_headers=mock_header -Dskywalking.plugin.springmvc.collect_http_params=true -jar ${agent_opts} ${home}/../libs/spring-boot-2.x-scenario.jar &
diff --git a/test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/spring-boot-2.x-scenario/config/expectedData.yaml
similarity index 77%
copy from test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml
copy to test/plugin/scenarios/spring-boot-2.x-scenario/config/expectedData.yaml
index 926a3f2b4c..a0c9365bd2 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/config/expectedData.yaml
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 segmentItems:
-- serviceName: spring-6.x-scenario
+- serviceName: spring-boot-2.x-scenario
   segmentSize: ge 10
   segments:
   - segmentId: not null
@@ -30,7 +30,7 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/healthCheck'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/healthCheck'}
       - {key: http.method, value: HEAD}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
@@ -80,14 +80,14 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/case/spring3'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/case/spring3'}
       - {key: http.method, value: GET}
       - {key: http.headers, value: 'mock_header=[mock_value]'}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-2.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -102,13 +102,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/create/'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/create/'}
       - {key: http.method, value: POST}
       - {key: http.status_code, value: '201'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 2, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-2.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -123,13 +123,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/get/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/get/1'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 3, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-2.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -144,13 +144,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/update/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/update/1'}
       - {key: http.method, value: PUT}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 4, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-2.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -165,13 +165,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/delete/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/delete/1'}
       - {key: http.method, value: DELETE}
       - {key: http.status_code, value: '204'}
       refs:
       - {parentEndpoint:  GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 5, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-2.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -186,13 +186,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/inherit/child/test'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/inherit/child/test'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 6, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-2.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -207,13 +207,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/impl/requestmapping'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/impl/requestmapping'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 7, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-2.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -228,17 +228,17 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/impl/restmapping'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/impl/restmapping'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 8, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-2.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
-    - operationName: /spring-6.x-scenario/case/spring3
+    - operationName: /spring-boot-2.x-scenario/case/spring3
       parentSpanId: 0
       spanId: 1
       spanLayer: Http
@@ -250,10 +250,10 @@ segmentItems:
       peer: localhost:8080
       tags:
       - {key: http.method, value: GET}
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/case/spring3'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/case/spring3'}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/create/
+    - operationName: /spring-boot-2.x-scenario/create/
       parentSpanId: 0
       spanId: 2
       spanLayer: Http
@@ -264,11 +264,11 @@ segmentItems:
       spanType: Exit
       peer: localhost:8080
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/create/'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/create/'}
       - {key: http.method, value: POST}
       - {key: http.status_code, value: '201'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/get/1
+    - operationName: /spring-boot-2.x-scenario/get/1
       parentSpanId: 0
       spanId: 3
       spanLayer: Http
@@ -279,11 +279,11 @@ segmentItems:
       spanType: Exit
       peer: localhost:8080
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/get/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/get/1'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/update/1
+    - operationName: /spring-boot-2.x-scenario/update/1
       parentSpanId: 0
       spanId: 4
       spanLayer: Http
@@ -294,11 +294,11 @@ segmentItems:
       spanType: Exit
       peer: localhost:8080
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/update/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/update/1'}
       - {key: http.method, value: PUT}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/delete/1
+    - operationName: /spring-boot-2.x-scenario/delete/1
       parentSpanId: 0
       spanId: 5
       spanLayer: Http
@@ -309,11 +309,11 @@ segmentItems:
       spanType: Exit
       peer: localhost:8080
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/delete/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/delete/1'}
       - {key: http.method, value: DELETE}
       - {key: http.status_code, value: '204'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/inherit/child/test
+    - operationName: /spring-boot-2.x-scenario/inherit/child/test
       parentSpanId: 0
       spanId: 6
       spanLayer: Http
@@ -325,10 +325,10 @@ segmentItems:
       peer: localhost:8080
       tags:
       - {key: http.method, value: GET}
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/inherit/child/test'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/inherit/child/test'}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/impl/requestmapping
+    - operationName: /spring-boot-2.x-scenario/impl/requestmapping
       parentSpanId: 0
       spanId: 7
       spanLayer: Http
@@ -340,10 +340,10 @@ segmentItems:
       peer: localhost:8080
       tags:
       - {key: http.method, value: GET}
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/impl/requestmapping'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/impl/requestmapping'}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/impl/restmapping
+    - operationName: /spring-boot-2.x-scenario/impl/restmapping
       parentSpanId: 0
       spanId: 8
       spanLayer: Http
@@ -355,7 +355,7 @@ segmentItems:
       peer: localhost:8080
       tags:
       - {key: http.method, value: GET}
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/impl/restmapping'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/impl/restmapping'}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
     - operationName: GET:/case/resttemplate
@@ -369,7 +369,11 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/case/resttemplate'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-2.x-scenario/case/resttemplate'}
       - {key: http.method, value: GET}
+      - key: http.params
+        value: |-
+          q1=[v1]
+          chinese=[中文]
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/resources/skywalking-plugin.def b/test/plugin/scenarios/spring-boot-2.x-scenario/configuration.yml
similarity index 72%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/resources/skywalking-plugin.def
rename to test/plugin/scenarios/spring-boot-2.x-scenario/configuration.yml
index a7828a8f4b..e698f0affb 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/configuration.yml
@@ -14,5 +14,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-jetty-server-11.x=org.apache.skywalking.apm.plugin.jetty.v11.server.define.JettyInstrumentation
-jetty-server-11.x=org.apache.skywalking.apm.plugin.jetty.v11.server.define.DispatcherInstrumentation
+type: jvm
+entryService: '"http://localhost:8080/spring-boot-2.x-scenario/case/resttemplate?q1=v1&chinese=%e4%b8%ad%e6%96%87"'
+healthCheck: http://localhost:8080/spring-boot-2.x-scenario/healthCheck
+startScript: ./bin/startup.sh
+runningMode: with_optional
+withPlugins: apm-spring-annotation-plugin-*.jar
diff --git a/test/plugin/scenarios/spring-boot-2.x-scenario/pom.xml b/test/plugin/scenarios/spring-boot-2.x-scenario/pom.xml
new file mode 100644
index 0000000000..e2b3b867a5
--- /dev/null
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/pom.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+<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.apache.skywalking</groupId>
+    <artifactId>spring-boot-2.x-scenario</artifactId>
+    <version>5.0.0</version>
+
+    <packaging>jar</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <compiler.version>8</compiler.version>
+        <maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
+        <!-- The Spring Boot version, overridden per entry in support-version.list via -Dtest.framework.version -->
+        <test.framework.version>2.7.18</test.framework.version>
+        <test.framework>spring-boot</test.framework>
+    </properties>
+
+    <name>skywalking-spring-boot-2.x-scenario</name>
+
+    <dependencies>
+        <!-- Spring Boot 2.x brings embedded Tomcat 9 (javax) + Spring MVC 5 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${test.framework.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+            <version>${test.framework.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>4.10.0</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>spring-boot-2.x-scenario</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${test.framework.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven-compiler-plugin.version}</version>
+                <configuration>
+                    <parameters>true</parameters>
+                    <source>${compiler.version}</source>
+                    <target>${compiler.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>assemble</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/assembly/assembly.xml</descriptor>
+                            </descriptors>
+                            <outputDirectory>./target/</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/assembly/assembly.xml
similarity index 51%
copy from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/assembly/assembly.xml
index 7c54849e28..c255ce5f79 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/assembly/assembly.xml
@@ -16,27 +16,26 @@
   ~ limitations under the License.
   ~
   -->
+<assembly
+    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+    <formats>
+        <format>zip</format>
+    </formats>
 
-<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">
-    <parent>
-        <artifactId>apm-sdk-plugin</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>9.7.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
+    <fileSets>
+        <fileSet>
+            <directory>./bin</directory>
+            <fileMode>0775</fileMode>
+        </fileSet>
+    </fileSets>
 
-    <artifactId>tomcat-10x-plugin</artifactId>
-
-    <properties>
-        <tomcat.version>10.0.22</tomcat.version>
-    </properties>
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.tomcat.embed</groupId>
-            <artifactId>tomcat-embed-core</artifactId>
-            <version>${tomcat.version}</version>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-
-</project>
+    <files>
+        <file>
+            <source>./target/spring-boot-2.x-scenario.jar</source>
+            <outputDirectory>./libs</outputDirectory>
+            <fileMode>0775</fileMode>
+        </file>
+    </files>
+</assembly>
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/Application.java
similarity index 67%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/Application.java
index d258f7a5f2..bdb91531cc 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/Application.java
@@ -16,22 +16,15 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
 
-public interface HttpServletRequestWrapper {
+@SpringBootApplication
+public class Application {
 
-    String getHeader(String name);
-
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/entity/User.java
similarity index 58%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/entity/User.java
index d258f7a5f2..e7fb1871e5 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/entity/User.java
@@ -16,22 +16,38 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.entity;
 
-import java.util.Enumeration;
-import java.util.Map;
+public class User {
 
-public interface HttpServletRequestWrapper {
+    private int id;
+    private String userName;
 
-    String getHeader(String name);
+    public User(int id) {
+        this.id = id;
+    }
 
-    String getMethod();
+    public User(int id, String userName) {
+        this.id = id;
+        this.userName = userName;
+    }
 
-    StringBuffer getRequestURL();
+    public User() {
+    }
 
-    String getRemoteHost();
+    public String getUserName() {
+        return userName;
+    }
 
-    Map<String, String[]> getParameterMap();
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
 
-    public Enumeration<String> getHeaders(String name);
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseController.java
similarity index 64%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseController.java
index d258f7a5f2..7a95a9318a 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseController.java
@@ -16,22 +16,20 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.implinterface;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.web.bind.annotation.RestController;
 
-public interface HttpServletRequestWrapper {
+@RestController
+public class TestCaseController implements TestCaseInterface {
 
-    String getHeader(String name);
+    @Override
+    public String implRequestMappingAnnotationTestCase() {
+        return "implRequestMappingAnnotationTestCase";
+    }
 
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    @Override
+    public String implRestAnnotationTestCase() {
+        return "implRestAnnotationTestCase";
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseInterface.java
similarity index 66%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseInterface.java
index d258f7a5f2..4fea97b7b1 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseInterface.java
@@ -16,22 +16,16 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.implinterface;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
 
-public interface HttpServletRequestWrapper {
+@RequestMapping("/impl")
+public interface TestCaseInterface {
+    @RequestMapping(path = "/requestmapping")
+    String implRequestMappingAnnotationTestCase();
 
-    String getHeader(String name);
-
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    @GetMapping("/restmapping")
+    String implRestAnnotationTestCase();
 }
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ChildController.java
similarity index 69%
copy from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ChildController.java
index 156bb0517b..27ddf54c76 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ChildController.java
@@ -6,7 +6,7 @@
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
- *    http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
+package test.apache.skywalking.apm.testcase.inherit;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/inherit/child")
+public class ChildController extends ParentController {
 
-public class Constants {
-    public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ParentController.java
similarity index 67%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ParentController.java
index d258f7a5f2..16b928100d 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ParentController.java
@@ -16,22 +16,17 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.inherit;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
-public interface HttpServletRequestWrapper {
+@RestController
+@RequestMapping("/inherit/parent")
+public class ParentController {
 
-    String getHeader(String name);
-
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    @RequestMapping("test")
+    public String test(Integer param) {
+        return "parent-a" + param;
+    }
 }
diff --git a/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/restapi/RestCaseController.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/restapi/RestCaseController.java
new file mode 100644
index 0000000000..6792ecb712
--- /dev/null
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/restapi/RestCaseController.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package test.apache.skywalking.apm.testcase.restapi;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.util.UriComponentsBuilder;
+import test.apache.skywalking.apm.testcase.entity.User;
+
+@RestController
+public class RestCaseController {
+
+    private static final Map<Integer, User> USERS = new ConcurrentHashMap<Integer, User>();
+
+    @GetMapping(value = "/get/{id}")
+    @ResponseBody
+    private ResponseEntity<User> getUser(@PathVariable("id") int id) throws InterruptedException {
+        User currentUser = new User(id, "a");
+        return ResponseEntity.ok(currentUser);
+    }
+
+    @PostMapping(value = "/create/")
+    @ResponseBody
+    public ResponseEntity<Void> createUser(@RequestBody User user,
+        UriComponentsBuilder ucBuilder) throws InterruptedException {
+        USERS.put(user.getId(), user);
+        HttpHeaders headers = new HttpHeaders();
+        headers.setLocation(ucBuilder.path("/get/{id}").buildAndExpand(user.getId()).toUri());
+        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
+    }
+
+    @PutMapping(value = "/update/{id}")
+    @ResponseBody
+    public ResponseEntity<User> updateUser(@PathVariable("id") int id,
+        @RequestBody User user) throws InterruptedException {
+        User currentUser = new User(id, user.getUserName());
+        return ResponseEntity.ok(currentUser);
+    }
+
+    @DeleteMapping(value = "/delete/{id}")
+    @ResponseBody
+    public ResponseEntity<Void> deleteUser(@PathVariable("id") int id) throws InterruptedException {
+        User currentUser = USERS.get(id);
+        if (currentUser == null) {
+            return ResponseEntity.noContent().build();
+        }
+        USERS.remove(id);
+        return ResponseEntity.noContent().build();
+    }
+}
diff --git a/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/resttemplate/RestTemplateController.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/resttemplate/RestTemplateController.java
new file mode 100644
index 0000000000..ba80f261b0
--- /dev/null
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/resttemplate/RestTemplateController.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package test.apache.skywalking.apm.testcase.resttemplate;
+
+import java.io.IOException;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.http.HttpEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+import test.apache.skywalking.apm.testcase.entity.User;
+
+@RestController
+public class RestTemplateController {
+
+    private static final String SUCCESS = "Success";
+
+    private static final Logger LOGGER = LogManager.getLogger(RestTemplateController.class);
+
+    private static final String URL = "http://localhost:8080/spring-boot-2.x-scenario";
+
+    @RequestMapping("/case/resttemplate")
+    @ResponseBody
+    public String restTemplate() throws IOException {
+        Request request = new Request.Builder().header("mock_header", "mock_value").url(URL + "/case/spring3").build();
+        Response response = new OkHttpClient().newCall(request).execute();
+        LOGGER.info(response.toString());
+
+        // Create user
+        HttpEntity<User> userEntity = new HttpEntity<>(new User(1, "a"));
+        new RestTemplate().postForEntity(URL + "/create/", userEntity, Void.class);
+
+        // Find User
+        new RestTemplate().getForEntity(URL + "/get/{id}", User.class, 1);
+
+        //Modify user
+        HttpEntity<User> updateUserEntity = new HttpEntity<>(new User(1, "b"));
+        new RestTemplate().put(URL + "/update/{id}", updateUserEntity, userEntity.getBody().getId(), 1);
+
+        //Delete user
+        new RestTemplate().delete(URL + "/delete/{id}", 1);
+
+        Request inheritRequest = new Request.Builder().url(URL + "/inherit/child/test").build();
+        response = new OkHttpClient().newCall(inheritRequest).execute();
+        LOGGER.info(response.toString());
+
+        Request implRequestMappingRequest = new Request.Builder().url(URL + "/impl/requestmapping").build();
+        response = new OkHttpClient().newCall(implRequestMappingRequest).execute();
+        LOGGER.info(response.toString());
+
+        Request implRestMappingRequest = new Request.Builder().url(URL + "/impl/restmapping").build();
+        response = new OkHttpClient().newCall(implRestMappingRequest).execute();
+        LOGGER.info(response.toString());
+
+        return SUCCESS;
+    }
+
+    @RequestMapping("/healthCheck")
+    @ResponseBody
+    public String healthCheck() {
+        return SUCCESS;
+    }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/CaseController.java
similarity index 53%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/CaseController.java
index d258f7a5f2..501c691579 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/CaseController.java
@@ -16,22 +16,26 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.spring3;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import test.apache.skywalking.apm.testcase.spring3.service.TestServiceBean;
 
-public interface HttpServletRequestWrapper {
+@Controller
+public class CaseController {
 
-    String getHeader(String name);
+    private static final String SUCCESS = "Success";
 
-    String getMethod();
+    @Autowired
+    private TestServiceBean testServiceBean;
 
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    @RequestMapping(value = "/case/spring3")
+    @ResponseBody
+    public String updateUser() {
+        testServiceBean.doSomeBusiness("test");
+        return SUCCESS;
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/component/TestComponentBean.java
similarity index 70%
copy from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/component/TestComponentBean.java
index 156bb0517b..274aaf490e 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/component/TestComponentBean.java
@@ -6,7 +6,7 @@
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
- *    http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
+package test.apache.skywalking.apm.testcase.spring3.component;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class TestComponentBean {
 
-public class Constants {
-    public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
+    public String componentMethod(String name) {
+        return name + "-" + "dealWith-component";
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/dao/TestRepositoryBean.java
similarity index 71%
copy from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/dao/TestRepositoryBean.java
index 156bb0517b..84f871ef55 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/dao/TestRepositoryBean.java
@@ -6,7 +6,7 @@
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
- *    http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
+package test.apache.skywalking.apm.testcase.spring3.dao;
+
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class TestRepositoryBean {
 
-public class Constants {
-    public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
+    public String doSomeStuff(String name) {
+        return name + "-dealWithRepository";
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/service/TestServiceBean.java
similarity index 56%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/service/TestServiceBean.java
index d258f7a5f2..811fe11648 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/service/TestServiceBean.java
@@ -16,22 +16,23 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.spring3.service;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import test.apache.skywalking.apm.testcase.spring3.dao.TestRepositoryBean;
+import test.apache.skywalking.apm.testcase.spring3.component.TestComponentBean;
 
-public interface HttpServletRequestWrapper {
+@Service
+public class TestServiceBean {
+    @Autowired
+    private TestComponentBean componentBean;
 
-    String getHeader(String name);
+    @Autowired
+    private TestRepositoryBean repositoryBean;
 
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    public void doSomeBusiness(String name) {
+        componentBean.componentMethod(name);
+        repositoryBean.doSomeStuff(name);
+    }
 }
diff --git a/test/plugin/scenarios/spring-6.x-scenario/support-version.list b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/resources/application.yml
similarity index 91%
copy from test/plugin/scenarios/spring-6.x-scenario/support-version.list
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/resources/application.yml
index c96f0b4304..e92dacba1a 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/support-version.list
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/resources/application.yml
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-6.0.4
-6.1.0
-6.1.1
+server:
+  port: 8080
+  servlet:
+    context-path: /spring-boot-2.x-scenario
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/resources/log4j2.xml
similarity index 50%
copy from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
copy to test/plugin/scenarios/spring-boot-2.x-scenario/src/main/resources/log4j2.xml
index 7c54849e28..b5cda5ae8a 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/src/main/resources/log4j2.xml
@@ -16,27 +16,15 @@
   ~ limitations under the License.
   ~
   -->
-
-<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">
-    <parent>
-        <artifactId>apm-sdk-plugin</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>9.7.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>tomcat-10x-plugin</artifactId>
-
-    <properties>
-        <tomcat.version>10.0.22</tomcat.version>
-    </properties>
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.tomcat.embed</groupId>
-            <artifactId>tomcat-embed-core</artifactId>
-            <version>${tomcat.version}</version>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-
-</project>
+<Configuration status="WARN">
+    <Appenders>
+        <Console name="Console" target="SYSTEM_ERR">
+            <PatternLayout charset="UTF-8" pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Root level="WARN">
+            <AppenderRef ref="Console"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git a/test/plugin/scenarios/spring-6.x-scenario/support-version.list b/test/plugin/scenarios/spring-boot-2.x-scenario/support-version.list
similarity index 81%
copy from test/plugin/scenarios/spring-6.x-scenario/support-version.list
copy to test/plugin/scenarios/spring-boot-2.x-scenario/support-version.list
index c96f0b4304..a1e6762600 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/support-version.list
+++ b/test/plugin/scenarios/spring-boot-2.x-scenario/support-version.list
@@ -14,6 +14,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-6.0.4
-6.1.0
-6.1.1
+# Spring Boot 2.x -> embedded Tomcat 9 (javax) + Spring MVC 5, one per minor (latest patch)
+2.0.9.RELEASE
+2.1.18.RELEASE
+2.2.13.RELEASE
+2.3.12.RELEASE
+2.4.13
+2.5.15
+2.6.15
+2.7.18
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/resources/skywalking-plugin.def b/test/plugin/scenarios/spring-boot-3.x-scenario/bin/startup.sh
similarity index 77%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/resources/skywalking-plugin.def
rename to test/plugin/scenarios/spring-boot-3.x-scenario/bin/startup.sh
index 915c014315..c72984e26c 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/bin/startup.sh
@@ -1,3 +1,5 @@
+#!/bin/bash
+#
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -14,5 +16,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-jetty-server-9.x=org.apache.skywalking.apm.plugin.jetty.v9.server.define.JettyInstrumentation
-jetty-server-9.x=org.apache.skywalking.apm.plugin.jetty.v9.server.define.DispatcherInstrumentation
+home="$(cd "$(dirname $0)"; pwd)"
+
+java -Dskywalking.plugin.http.include_http_headers=mock_header -Dskywalking.plugin.springmvc.collect_http_params=true -jar ${agent_opts} ${home}/../libs/spring-boot-3.x-scenario.jar &
diff --git a/test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml b/test/plugin/scenarios/spring-boot-3.x-scenario/config/expectedData.yaml
similarity index 77%
copy from test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml
copy to test/plugin/scenarios/spring-boot-3.x-scenario/config/expectedData.yaml
index 926a3f2b4c..a80d126128 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/config/expectedData.yaml
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/config/expectedData.yaml
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 segmentItems:
-- serviceName: spring-6.x-scenario
+- serviceName: spring-boot-3.x-scenario
   segmentSize: ge 10
   segments:
   - segmentId: not null
@@ -30,7 +30,7 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/healthCheck'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/healthCheck'}
       - {key: http.method, value: HEAD}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
@@ -80,14 +80,14 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/case/spring3'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/case/spring3'}
       - {key: http.method, value: GET}
       - {key: http.headers, value: 'mock_header=[mock_value]'}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 1, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-3.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -102,13 +102,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/create/'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/create/'}
       - {key: http.method, value: POST}
       - {key: http.status_code, value: '201'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 2, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-3.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -123,13 +123,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/get/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/get/1'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 3, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-3.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -144,13 +144,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/update/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/update/1'}
       - {key: http.method, value: PUT}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 4, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-3.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -165,13 +165,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/delete/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/delete/1'}
       - {key: http.method, value: DELETE}
       - {key: http.status_code, value: '204'}
       refs:
       - {parentEndpoint:  GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 5, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-3.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -186,13 +186,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/inherit/child/test'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/inherit/child/test'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 6, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-3.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -207,13 +207,13 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/impl/requestmapping'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/impl/requestmapping'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 7, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-3.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
@@ -228,17 +228,17 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/impl/restmapping'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/impl/restmapping'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       refs:
       - {parentEndpoint: GET:/case/resttemplate, networkAddress: 'localhost:8080', refType: CrossProcess,
         parentSpanId: 8, parentTraceSegmentId: not null, parentServiceInstance: not
-          null, parentService: spring-6.x-scenario, traceId: not null}
+          null, parentService: spring-boot-3.x-scenario, traceId: not null}
       skipAnalysis: 'false'
   - segmentId: not null
     spans:
-    - operationName: /spring-6.x-scenario/case/spring3
+    - operationName: /spring-boot-3.x-scenario/case/spring3
       parentSpanId: 0
       spanId: 1
       spanLayer: Http
@@ -250,10 +250,10 @@ segmentItems:
       peer: localhost:8080
       tags:
       - {key: http.method, value: GET}
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/case/spring3'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/case/spring3'}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/create/
+    - operationName: /spring-boot-3.x-scenario/create/
       parentSpanId: 0
       spanId: 2
       spanLayer: Http
@@ -264,11 +264,11 @@ segmentItems:
       spanType: Exit
       peer: localhost:8080
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/create/'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/create/'}
       - {key: http.method, value: POST}
       - {key: http.status_code, value: '201'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/get/1
+    - operationName: /spring-boot-3.x-scenario/get/1
       parentSpanId: 0
       spanId: 3
       spanLayer: Http
@@ -279,11 +279,11 @@ segmentItems:
       spanType: Exit
       peer: localhost:8080
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/get/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/get/1'}
       - {key: http.method, value: GET}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/update/1
+    - operationName: /spring-boot-3.x-scenario/update/1
       parentSpanId: 0
       spanId: 4
       spanLayer: Http
@@ -294,11 +294,11 @@ segmentItems:
       spanType: Exit
       peer: localhost:8080
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/update/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/update/1'}
       - {key: http.method, value: PUT}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/delete/1
+    - operationName: /spring-boot-3.x-scenario/delete/1
       parentSpanId: 0
       spanId: 5
       spanLayer: Http
@@ -309,11 +309,11 @@ segmentItems:
       spanType: Exit
       peer: localhost:8080
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/delete/1'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/delete/1'}
       - {key: http.method, value: DELETE}
       - {key: http.status_code, value: '204'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/inherit/child/test
+    - operationName: /spring-boot-3.x-scenario/inherit/child/test
       parentSpanId: 0
       spanId: 6
       spanLayer: Http
@@ -325,10 +325,10 @@ segmentItems:
       peer: localhost:8080
       tags:
       - {key: http.method, value: GET}
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/inherit/child/test'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/inherit/child/test'}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/impl/requestmapping
+    - operationName: /spring-boot-3.x-scenario/impl/requestmapping
       parentSpanId: 0
       spanId: 7
       spanLayer: Http
@@ -340,10 +340,10 @@ segmentItems:
       peer: localhost:8080
       tags:
       - {key: http.method, value: GET}
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/impl/requestmapping'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/impl/requestmapping'}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
-    - operationName: /spring-6.x-scenario/impl/restmapping
+    - operationName: /spring-boot-3.x-scenario/impl/restmapping
       parentSpanId: 0
       spanId: 8
       spanLayer: Http
@@ -355,7 +355,7 @@ segmentItems:
       peer: localhost:8080
       tags:
       - {key: http.method, value: GET}
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/impl/restmapping'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/impl/restmapping'}
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
     - operationName: GET:/case/resttemplate
@@ -369,7 +369,11 @@ segmentItems:
       spanType: Entry
       peer: ''
       tags:
-      - {key: url, value: 'http://localhost:8080/spring-6.x-scenario/case/resttemplate'}
+      - {key: url, value: 'http://localhost:8080/spring-boot-3.x-scenario/case/resttemplate'}
       - {key: http.method, value: GET}
+      - key: http.params
+        value: |-
+          q1=[v1]
+          chinese=[中文]
       - {key: http.status_code, value: '200'}
       skipAnalysis: 'false'
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def b/test/plugin/scenarios/spring-boot-3.x-scenario/configuration.yml
similarity index 70%
rename from apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def
rename to test/plugin/scenarios/spring-boot-3.x-scenario/configuration.yml
index 761d3970d3..0263142980 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-7.x-8.x-plugin/src/main/resources/skywalking-plugin.def
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/configuration.yml
@@ -14,5 +14,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-tomcat-7.x/8.x=org.apache.skywalking.apm.plugin.tomcat78x.define.TomcatInstrumentation
-tomcat-7.x/8.x=org.apache.skywalking.apm.plugin.tomcat78x.define.ApplicationDispatcherInstrumentation
+type: jvm
+entryService: '"http://localhost:8080/spring-boot-3.x-scenario/case/resttemplate?q1=v1&chinese=%e4%b8%ad%e6%96%87"'
+healthCheck: http://localhost:8080/spring-boot-3.x-scenario/healthCheck
+startScript: ./bin/startup.sh
+runningMode: with_optional
+withPlugins: apm-spring-annotation-plugin-*.jar;apm-*-6.x-plugin-*.jar
diff --git a/test/plugin/scenarios/spring-boot-3.x-scenario/pom.xml b/test/plugin/scenarios/spring-boot-3.x-scenario/pom.xml
new file mode 100644
index 0000000000..3f9bddf53d
--- /dev/null
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/pom.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+<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.apache.skywalking</groupId>
+    <artifactId>spring-boot-3.x-scenario</artifactId>
+    <version>5.0.0</version>
+
+    <packaging>jar</packaging>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <compiler.version>17</compiler.version>
+        <maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
+        <!-- The Spring Boot version, overridden per entry in support-version.list via -Dtest.framework.version -->
+        <test.framework.version>3.5.16</test.framework.version>
+        <test.framework>spring-boot</test.framework>
+    </properties>
+
+    <name>skywalking-spring-boot-3.x-scenario</name>
+
+    <dependencies>
+        <!-- Spring Boot 3.x brings embedded Tomcat 10 (jakarta) + Spring MVC 6 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${test.framework.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+            <version>${test.framework.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>4.10.0</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>spring-boot-3.x-scenario</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${test.framework.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven-compiler-plugin.version}</version>
+                <configuration>
+                    <parameters>true</parameters>
+                    <source>${compiler.version}</source>
+                    <target>${compiler.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>assemble</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/assembly/assembly.xml</descriptor>
+                            </descriptors>
+                            <outputDirectory>./target/</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>spring-snapshots</id>
+            <url>https://repo.spring.io/snapshot</url>
+        </pluginRepository>
+        <pluginRepository>
+            <id>spring-milestones</id>
+            <url>https://repo.spring.io/milestone</url>
+        </pluginRepository>
+    </pluginRepositories>
+</project>
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/assembly/assembly.xml
similarity index 51%
copy from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
copy to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/assembly/assembly.xml
index 7c54849e28..fcd1eab0d8 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/assembly/assembly.xml
@@ -16,27 +16,26 @@
   ~ limitations under the License.
   ~
   -->
+<assembly
+    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
+    <formats>
+        <format>zip</format>
+    </formats>
 
-<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">
-    <parent>
-        <artifactId>apm-sdk-plugin</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>9.7.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
+    <fileSets>
+        <fileSet>
+            <directory>./bin</directory>
+            <fileMode>0775</fileMode>
+        </fileSet>
+    </fileSets>
 
-    <artifactId>tomcat-10x-plugin</artifactId>
-
-    <properties>
-        <tomcat.version>10.0.22</tomcat.version>
-    </properties>
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.tomcat.embed</groupId>
-            <artifactId>tomcat-embed-core</artifactId>
-            <version>${tomcat.version}</version>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-
-</project>
+    <files>
+        <file>
+            <source>./target/spring-boot-3.x-scenario.jar</source>
+            <outputDirectory>./libs</outputDirectory>
+            <fileMode>0775</fileMode>
+        </file>
+    </files>
+</assembly>
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/Application.java
similarity index 67%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/Application.java
index d258f7a5f2..bdb91531cc 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/Application.java
@@ -16,22 +16,15 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
 
-public interface HttpServletRequestWrapper {
+@SpringBootApplication
+public class Application {
 
-    String getHeader(String name);
-
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/entity/User.java
similarity index 58%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/entity/User.java
index d258f7a5f2..e7fb1871e5 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/entity/User.java
@@ -16,22 +16,38 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.entity;
 
-import java.util.Enumeration;
-import java.util.Map;
+public class User {
 
-public interface HttpServletRequestWrapper {
+    private int id;
+    private String userName;
 
-    String getHeader(String name);
+    public User(int id) {
+        this.id = id;
+    }
 
-    String getMethod();
+    public User(int id, String userName) {
+        this.id = id;
+        this.userName = userName;
+    }
 
-    StringBuffer getRequestURL();
+    public User() {
+    }
 
-    String getRemoteHost();
+    public String getUserName() {
+        return userName;
+    }
 
-    Map<String, String[]> getParameterMap();
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
 
-    public Enumeration<String> getHeaders(String name);
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseController.java
similarity index 64%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseController.java
index d258f7a5f2..7a95a9318a 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseController.java
@@ -16,22 +16,20 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.implinterface;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.web.bind.annotation.RestController;
 
-public interface HttpServletRequestWrapper {
+@RestController
+public class TestCaseController implements TestCaseInterface {
 
-    String getHeader(String name);
+    @Override
+    public String implRequestMappingAnnotationTestCase() {
+        return "implRequestMappingAnnotationTestCase";
+    }
 
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    @Override
+    public String implRestAnnotationTestCase() {
+        return "implRestAnnotationTestCase";
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseInterface.java
similarity index 66%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseInterface.java
index d258f7a5f2..4fea97b7b1 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/implinterface/TestCaseInterface.java
@@ -16,22 +16,16 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.implinterface;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
 
-public interface HttpServletRequestWrapper {
+@RequestMapping("/impl")
+public interface TestCaseInterface {
+    @RequestMapping(path = "/requestmapping")
+    String implRequestMappingAnnotationTestCase();
 
-    String getHeader(String name);
-
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    @GetMapping("/restmapping")
+    String implRestAnnotationTestCase();
 }
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ChildController.java
similarity index 69%
copy from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
copy to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ChildController.java
index 156bb0517b..27ddf54c76 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ChildController.java
@@ -6,7 +6,7 @@
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
- *    http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
+package test.apache.skywalking.apm.testcase.inherit;
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/inherit/child")
+public class ChildController extends ParentController {
 
-public class Constants {
-    public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ParentController.java
similarity index 67%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ParentController.java
index d258f7a5f2..16b928100d 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/inherit/ParentController.java
@@ -16,22 +16,17 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.inherit;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
-public interface HttpServletRequestWrapper {
+@RestController
+@RequestMapping("/inherit/parent")
+public class ParentController {
 
-    String getHeader(String name);
-
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    @RequestMapping("test")
+    public String test(Integer param) {
+        return "parent-a" + param;
+    }
 }
diff --git a/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/restapi/RestCaseController.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/restapi/RestCaseController.java
new file mode 100644
index 0000000000..6792ecb712
--- /dev/null
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/restapi/RestCaseController.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package test.apache.skywalking.apm.testcase.restapi;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.util.UriComponentsBuilder;
+import test.apache.skywalking.apm.testcase.entity.User;
+
+@RestController
+public class RestCaseController {
+
+    private static final Map<Integer, User> USERS = new ConcurrentHashMap<Integer, User>();
+
+    @GetMapping(value = "/get/{id}")
+    @ResponseBody
+    private ResponseEntity<User> getUser(@PathVariable("id") int id) throws InterruptedException {
+        User currentUser = new User(id, "a");
+        return ResponseEntity.ok(currentUser);
+    }
+
+    @PostMapping(value = "/create/")
+    @ResponseBody
+    public ResponseEntity<Void> createUser(@RequestBody User user,
+        UriComponentsBuilder ucBuilder) throws InterruptedException {
+        USERS.put(user.getId(), user);
+        HttpHeaders headers = new HttpHeaders();
+        headers.setLocation(ucBuilder.path("/get/{id}").buildAndExpand(user.getId()).toUri());
+        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
+    }
+
+    @PutMapping(value = "/update/{id}")
+    @ResponseBody
+    public ResponseEntity<User> updateUser(@PathVariable("id") int id,
+        @RequestBody User user) throws InterruptedException {
+        User currentUser = new User(id, user.getUserName());
+        return ResponseEntity.ok(currentUser);
+    }
+
+    @DeleteMapping(value = "/delete/{id}")
+    @ResponseBody
+    public ResponseEntity<Void> deleteUser(@PathVariable("id") int id) throws InterruptedException {
+        User currentUser = USERS.get(id);
+        if (currentUser == null) {
+            return ResponseEntity.noContent().build();
+        }
+        USERS.remove(id);
+        return ResponseEntity.noContent().build();
+    }
+}
diff --git a/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/resttemplate/RestTemplateController.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/resttemplate/RestTemplateController.java
new file mode 100644
index 0000000000..89947c72d6
--- /dev/null
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/resttemplate/RestTemplateController.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package test.apache.skywalking.apm.testcase.resttemplate;
+
+import java.io.IOException;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.http.HttpEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.RestTemplate;
+import test.apache.skywalking.apm.testcase.entity.User;
+
+@RestController
+public class RestTemplateController {
+
+    private static final String SUCCESS = "Success";
+
+    private static final Logger LOGGER = LogManager.getLogger(RestTemplateController.class);
+
+    private static final String URL = "http://localhost:8080/spring-boot-3.x-scenario";
+
+    @RequestMapping("/case/resttemplate")
+    @ResponseBody
+    public String restTemplate() throws IOException {
+        Request request = new Request.Builder().header("mock_header", "mock_value").url(URL + "/case/spring3").build();
+        Response response = new OkHttpClient().newCall(request).execute();
+        LOGGER.info(response.toString());
+
+        // Create user
+        HttpEntity<User> userEntity = new HttpEntity<>(new User(1, "a"));
+        new RestTemplate().postForEntity(URL + "/create/", userEntity, Void.class);
+
+        // Find User
+        new RestTemplate().getForEntity(URL + "/get/{id}", User.class, 1);
+
+        //Modify user
+        HttpEntity<User> updateUserEntity = new HttpEntity<>(new User(1, "b"));
+        new RestTemplate().put(URL + "/update/{id}", updateUserEntity, userEntity.getBody().getId(), 1);
+
+        //Delete user
+        new RestTemplate().delete(URL + "/delete/{id}", 1);
+
+        Request inheritRequest = new Request.Builder().url(URL + "/inherit/child/test").build();
+        response = new OkHttpClient().newCall(inheritRequest).execute();
+        LOGGER.info(response.toString());
+
+        Request implRequestMappingRequest = new Request.Builder().url(URL + "/impl/requestmapping").build();
+        response = new OkHttpClient().newCall(implRequestMappingRequest).execute();
+        LOGGER.info(response.toString());
+
+        Request implRestMappingRequest = new Request.Builder().url(URL + "/impl/restmapping").build();
+        response = new OkHttpClient().newCall(implRestMappingRequest).execute();
+        LOGGER.info(response.toString());
+
+        return SUCCESS;
+    }
+
+    @RequestMapping("/healthCheck")
+    @ResponseBody
+    public String healthCheck() {
+        return SUCCESS;
+    }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/CaseController.java
similarity index 53%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
copy to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/CaseController.java
index d258f7a5f2..501c691579 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/CaseController.java
@@ -16,22 +16,26 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.spring3;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import test.apache.skywalking.apm.testcase.spring3.service.TestServiceBean;
 
-public interface HttpServletRequestWrapper {
+@Controller
+public class CaseController {
 
-    String getHeader(String name);
+    private static final String SUCCESS = "Success";
 
-    String getMethod();
+    @Autowired
+    private TestServiceBean testServiceBean;
 
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    @RequestMapping(value = "/case/spring3")
+    @ResponseBody
+    public String updateUser() {
+        testServiceBean.doSomeBusiness("test");
+        return SUCCESS;
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/component/TestComponentBean.java
similarity index 70%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
rename to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/component/TestComponentBean.java
index 156bb0517b..274aaf490e 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-11.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v11/server/Constants.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/component/TestComponentBean.java
@@ -6,7 +6,7 @@
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
- *    http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v11.server;
+package test.apache.skywalking.apm.testcase.spring3.component;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class TestComponentBean {
 
-public class Constants {
-    public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
+    public String componentMethod(String name) {
+        return name + "-" + "dealWith-component";
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/Constants.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/dao/TestRepositoryBean.java
similarity index 71%
rename from apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/Constants.java
rename to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/dao/TestRepositoryBean.java
index e1e8d84d65..84f871ef55 100644
--- a/apm-sniffer/apm-sdk-plugin/jetty-plugin/jetty-server-9.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/jetty/v9/server/Constants.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/dao/TestRepositoryBean.java
@@ -6,7 +6,7 @@
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
  *
- *    http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,11 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  *
- *
  */
 
-package org.apache.skywalking.apm.plugin.jetty.v9.server;
+package test.apache.skywalking.apm.testcase.spring3.dao;
+
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class TestRepositoryBean {
 
-public class Constants {
-    public static final String FORWARD_REQUEST_FLAG = "SW_FORWARD_REQUEST_FLAG";
+    public String doSomeStuff(String name) {
+        return name + "-dealWithRepository";
+    }
 }
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/service/TestServiceBean.java
similarity index 56%
rename from apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
rename to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/service/TestServiceBean.java
index d258f7a5f2..811fe11648 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/HttpServletRequestWrapper.java
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/java/test/apache/skywalking/apm/testcase/spring3/service/TestServiceBean.java
@@ -16,22 +16,23 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.spring3.service;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import test.apache.skywalking.apm.testcase.spring3.dao.TestRepositoryBean;
+import test.apache.skywalking.apm.testcase.spring3.component.TestComponentBean;
 
-public interface HttpServletRequestWrapper {
+@Service
+public class TestServiceBean {
+    @Autowired
+    private TestComponentBean componentBean;
 
-    String getHeader(String name);
+    @Autowired
+    private TestRepositoryBean repositoryBean;
 
-    String getMethod();
-
-    StringBuffer getRequestURL();
-
-    String getRemoteHost();
-
-    Map<String, String[]> getParameterMap();
-
-    public Enumeration<String> getHeaders(String name);
+    public void doSomeBusiness(String name) {
+        componentBean.componentMethod(name);
+        repositoryBean.doSomeStuff(name);
+    }
 }
diff --git a/test/plugin/scenarios/spring-6.x-scenario/support-version.list b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/resources/application.yml
similarity index 91%
copy from test/plugin/scenarios/spring-6.x-scenario/support-version.list
copy to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/resources/application.yml
index c96f0b4304..e67ba613ef 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/support-version.list
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/resources/application.yml
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-6.0.4
-6.1.0
-6.1.1
+server:
+  port: 8080
+  servlet:
+    context-path: /spring-boot-3.x-scenario
diff --git a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/resources/log4j2.xml
similarity index 50%
rename from apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
rename to test/plugin/scenarios/spring-boot-3.x-scenario/src/main/resources/log4j2.xml
index 7c54849e28..b5cda5ae8a 100644
--- a/apm-sniffer/apm-sdk-plugin/tomcat-10x-plugin/pom.xml
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/src/main/resources/log4j2.xml
@@ -16,27 +16,15 @@
   ~ limitations under the License.
   ~
   -->
-
-<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">
-    <parent>
-        <artifactId>apm-sdk-plugin</artifactId>
-        <groupId>org.apache.skywalking</groupId>
-        <version>9.7.0-SNAPSHOT</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>tomcat-10x-plugin</artifactId>
-
-    <properties>
-        <tomcat.version>10.0.22</tomcat.version>
-    </properties>
-    <dependencies>
-        <dependency>
-            <groupId>org.apache.tomcat.embed</groupId>
-            <artifactId>tomcat-embed-core</artifactId>
-            <version>${tomcat.version}</version>
-            <scope>provided</scope>
-        </dependency>
-    </dependencies>
-
-</project>
+<Configuration status="WARN">
+    <Appenders>
+        <Console name="Console" target="SYSTEM_ERR">
+            <PatternLayout charset="UTF-8" pattern="[%d{yyyy-MM-dd HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Root level="WARN">
+            <AppenderRef ref="Console"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git a/test/plugin/scenarios/spring-6.x-scenario/support-version.list b/test/plugin/scenarios/spring-boot-3.x-scenario/support-version.list
similarity index 94%
copy from test/plugin/scenarios/spring-6.x-scenario/support-version.list
copy to test/plugin/scenarios/spring-boot-3.x-scenario/support-version.list
index c96f0b4304..1f8df5c9b3 100644
--- a/test/plugin/scenarios/spring-6.x-scenario/support-version.list
+++ b/test/plugin/scenarios/spring-boot-3.x-scenario/support-version.list
@@ -14,6 +14,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-6.0.4
-6.1.0
-6.1.1
+3.0.13
+3.1.12
+3.2.12
+3.3.13
+3.4.13
+3.5.16
diff --git a/test/plugin/scenarios/undertow-2.3.x-scenario/support-version.list b/test/plugin/scenarios/undertow-2.3.x-scenario/support-version.list
index a3dca1ddcf..1f4d4b5614 100644
--- a/test/plugin/scenarios/undertow-2.3.x-scenario/support-version.list
+++ b/test/plugin/scenarios/undertow-2.3.x-scenario/support-version.list
@@ -14,5 +14,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Undertow 2.3.x requires Java 11+, tested with JDK 17
-2.3.18.Final
+# Undertow 2.3.x requires Java 11+; 2.4.x requires Java 17. Tested with JDK 17.
+2.3.25.Final
+2.4.2.Final