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

wusheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/skywalking.git


The following commit(s) were added to refs/heads/master by this push:
     new b732ff3  Fix ClassCast issue for RequestHolder/ResponseHolder (#6973)
b732ff3 is described below

commit b732ff35a7fd0d99ef1e5f4b9a66170fa812f6cd
Author: Lu Jiajing <[email protected]>
AuthorDate: Sat May 22 17:06:13 2021 +0800

    Fix ClassCast issue for RequestHolder/ResponseHolder (#6973)
---
 .github/workflows/plugins-test.0.yaml              |   1 +
 CHANGES.md                                         |   1 +
 .../core/context/ContextManagerBenchmark.java      |  97 +++++++++++
 .../mvc/v3/HandlerMethodInvokerInterceptor.java    |   5 +-
 .../plugin/spring/mvc/v4/SpringTestCaseHelper.java |   6 +-
 .../plugin/spring/mvc/v5/GetBeanInterceptor.java   |   6 +-
 .../plugin/spring/mvc/v5/InvokeInterceptor.java    |  62 +++----
 .../v5/define/AbstractSpring5Instrumentation.java  |   4 +-
 .../AbstractSpring5ReactiveInstrumentation.java    |   4 +-
 ... AbstractSpring5ReactiveInstrumentationV2.java} |   8 +-
 .../InvocableHandlerMethodInstrumentation.java     |  13 +-
 .../apm/plugin/spring/mvc/commons/Constants.java   |   2 +
 .../mvc/commons/JavaxServletRequestHolder.java     |  56 -------
 .../spring/mvc/commons/ReactiveRequestHolder.java  |  66 --------
 .../spring/mvc/commons/ReactiveResponseHolder.java |  45 -----
 .../apm/plugin/spring/mvc/commons/RequestUtil.java | 110 ++++++++++++
 .../plugin/spring/mvc/commons/ResponseHolder.java  |  22 ---
 .../interceptor/AbstractMethodInterceptor.java     | 186 +++++++++++----------
 .../commons/interceptor/GetBeanInterceptor.java    |   5 +-
 .../interceptor/InvokeForRequestInterceptor.java   |   5 +-
 .../InvokeHandlerMethodInterceptor.java            |  13 +-
 .../bin/startup.sh                                 |  24 +++
 .../config/expectedData.yaml                       | 103 ++++++++++++
 .../configuration.yml                              |  20 +++
 .../pom.xml                                        |  35 +++-
 .../src/main/assembly/assembly.xml                 |  49 ++++++
 .../testcase/sc/springmvcreactive/Application.java |  20 +--
 .../springmvcreactive/controller/Controller.java   |  60 +++++++
 .../sc/springmvcreactive/service/TestService.java  |  25 ++-
 .../src/main/resources/application.yml             |  18 ++
 .../support-version.list                           |  20 +++
 .../scenarios/springmvc-reactive-scenario/pom.xml  |   2 +-
 32 files changed, 719 insertions(+), 374 deletions(-)

diff --git a/.github/workflows/plugins-test.0.yaml 
b/.github/workflows/plugins-test.0.yaml
index b627277..43cf875 100644
--- a/.github/workflows/plugins-test.0.yaml
+++ b/.github/workflows/plugins-test.0.yaml
@@ -69,6 +69,7 @@ jobs:
           - gson-scenario
           - elasticjob-3.x-scenario
           - springmvc-reactive-scenario
+          - springmvc-reactive-devtools-scenario
     steps:
       - uses: actions/checkout@v2
         with:
diff --git a/CHANGES.md b/CHANGES.md
index 36d3685..7eb1499 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -30,6 +30,7 @@ Release Notes.
 * Fix the conversion problem of float type in ConfigInitializer.
 * Fixed part of the dynamic configuration of ConfigurationDiscoveryService 
that does not take effect under certain circumstances.
 * Introduce method interceptor API v2
+* Fix ClassCast issue for RequestHolder/ResponseHolder.
 
 #### OAP-Backend
 * BugFix: filter invalid Envoy access logs whose socket address is empty.
diff --git 
a/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/ContextManagerBenchmark.java
 
b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/ContextManagerBenchmark.java
new file mode 100644
index 0000000..8810129
--- /dev/null
+++ 
b/apm-sniffer/apm-agent-core/src/test/java/org/apache/skywalking/apm/agent/core/context/ContextManagerBenchmark.java
@@ -0,0 +1,97 @@
+/*
+ * 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.agent.core.context;
+
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.BenchmarkMode;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Mode;
+import org.openjdk.jmh.annotations.OutputTimeUnit;
+import org.openjdk.jmh.infra.Blackhole;
+import org.openjdk.jmh.profile.GCProfiler;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class ContextManagerBenchmark {
+    @Benchmark
+    @Fork(value = 1, warmups = 1)
+    @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    @BenchmarkMode(Mode.SampleTime)
+    public void getKeyFromThreadLocal(Blackhole bh) {
+        bh.consume(ContextManager.getRuntimeContext().get("KEY"));
+    }
+
+    @Benchmark
+    @Fork(value = 1, warmups = 1)
+    @OutputTimeUnit(TimeUnit.NANOSECONDS)
+    @BenchmarkMode(Mode.SampleTime)
+    public void isAssignableFrom(Blackhole bh) {
+        bh.consume(Map.class.isAssignableFrom(HashMap.class));
+    }
+
+    public static void main(String[] args) throws Exception {
+        Options opt = new 
OptionsBuilder().include(ContextManagerBenchmark.class.getSimpleName())
+                .addProfiler(GCProfiler.class)
+                .build();
+        new Runner(opt).run();
+    }
+
+    /**
+     * # JMH version: 1.21
+     * # VM version: JDK 1.8.0_292, OpenJDK 64-Bit Server VM, 25.292-b10
+     * # VM invoker: 
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/bin/java
+     * # VM options: -javaagent:/Applications/IntelliJ 
IDEA.app/Contents/lib/idea_rt.jar=62459:/Applications/IntelliJ 
IDEA.app/Contents/bin -Dfile.encoding=UTF-8
+     * # Warmup: 5 iterations, 10 s each
+     * # Measurement: 5 iterations, 10 s each
+     * # Timeout: 10 min per iteration
+     * # Threads: 1 thread, will synchronize iterations
+     * # Benchmark mode: Sampling time
+     *
+     * Benchmark                                                               
       Mode      Cnt       Score    Error   Units
+     * ContextManagerBenchmark.getKeyFromThreadLocal                           
     sample  1332415      48.066 ±  0.765   ns/op
+     * 
ContextManagerBenchmark.getKeyFromThreadLocal:getKeyFromThreadLocal·p0.00    
sample               11.000            ns/op
+     * 
ContextManagerBenchmark.getKeyFromThreadLocal:getKeyFromThreadLocal·p0.50    
sample               42.000            ns/op
+     * 
ContextManagerBenchmark.getKeyFromThreadLocal:getKeyFromThreadLocal·p0.90    
sample               45.000            ns/op
+     * 
ContextManagerBenchmark.getKeyFromThreadLocal:getKeyFromThreadLocal·p0.95    
sample               47.000            ns/op
+     * 
ContextManagerBenchmark.getKeyFromThreadLocal:getKeyFromThreadLocal·p0.99    
sample               93.000            ns/op
+     * 
ContextManagerBenchmark.getKeyFromThreadLocal:getKeyFromThreadLocal·p0.999   
sample              652.000            ns/op
+     * 
ContextManagerBenchmark.getKeyFromThreadLocal:getKeyFromThreadLocal·p0.9999  
sample            11236.403            ns/op
+     * 
ContextManagerBenchmark.getKeyFromThreadLocal:getKeyFromThreadLocal·p1.00    
sample           144384.000            ns/op
+     * ContextManagerBenchmark.getKeyFromThreadLocal:·gc.alloc.rate            
     sample        5       0.022 ±  0.010  MB/sec
+     * ContextManagerBenchmark.getKeyFromThreadLocal:·gc.alloc.rate.norm       
     sample        5      ≈ 10⁻⁴             B/op
+     * ContextManagerBenchmark.getKeyFromThreadLocal:·gc.count                 
     sample        5         ≈ 0           counts
+     * ContextManagerBenchmark.isAssignableFrom                                
     sample  1182629      45.894 ±  0.939   ns/op
+     * ContextManagerBenchmark.isAssignableFrom:isAssignableFrom·p0.00         
     sample                7.000            ns/op
+     * ContextManagerBenchmark.isAssignableFrom:isAssignableFrom·p0.50         
     sample               39.000            ns/op
+     * ContextManagerBenchmark.isAssignableFrom:isAssignableFrom·p0.90         
     sample               43.000            ns/op
+     * ContextManagerBenchmark.isAssignableFrom:isAssignableFrom·p0.95         
     sample               46.000            ns/op
+     * ContextManagerBenchmark.isAssignableFrom:isAssignableFrom·p0.99         
     sample               89.000            ns/op
+     * ContextManagerBenchmark.isAssignableFrom:isAssignableFrom·p0.999        
     sample              606.000            ns/op
+     * ContextManagerBenchmark.isAssignableFrom:isAssignableFrom·p0.9999       
     sample            15904.000            ns/op
+     * ContextManagerBenchmark.isAssignableFrom:isAssignableFrom·p1.00         
     sample           138240.000            ns/op
+     * ContextManagerBenchmark.isAssignableFrom:·gc.alloc.rate                 
     sample        5       0.021 ±  0.007  MB/sec
+     * ContextManagerBenchmark.isAssignableFrom:·gc.alloc.rate.norm            
     sample        5      ≈ 10⁻⁴             B/op
+     * ContextManagerBenchmark.isAssignableFrom:·gc.count                      
     sample        5         ≈ 0           counts
+     */
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v3/HandlerMethodInvokerInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v3/HandlerMethodInvokerInterceptor.java
index dd60587..2123338 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v3/HandlerMethodInvokerInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-3.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v3/HandlerMethodInvokerInterceptor.java
@@ -19,12 +19,10 @@
 package org.apache.skywalking.apm.plugin.spring.mvc.v3;
 
 import java.lang.reflect.Method;
-import javax.servlet.http.HttpServletResponse;
 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;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.JavaxServletResponseHolder;
 import org.springframework.web.context.request.NativeWebRequest;
 
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT;
@@ -40,8 +38,7 @@ public class HandlerMethodInvokerInterceptor implements 
InstanceMethodsAroundInt
         Object handler = allArguments[1];
         if (handler instanceof EnhancedInstance) {
             ContextManager.getRuntimeContext()
-                          .put(RESPONSE_KEY_IN_RUNTIME_CONTEXT, new 
JavaxServletResponseHolder(
-                              (HttpServletResponse) ((NativeWebRequest) 
allArguments[2]).getNativeResponse()));
+                          .put(RESPONSE_KEY_IN_RUNTIME_CONTEXT, 
((NativeWebRequest) allArguments[2]).getNativeResponse());
         }
     }
 
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/mvc/v4/SpringTestCaseHelper.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/mvc/v4/SpringTestCaseHelper.java
index 2447d20..ffcee2a 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/mvc/v4/SpringTestCaseHelper.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-4.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/mvc/v4/SpringTestCaseHelper.java
@@ -22,16 +22,14 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.apache.skywalking.apm.agent.core.context.ContextManager;
 import org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.JavaxServletRequestHolder;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.JavaxServletResponseHolder;
 
 public final class SpringTestCaseHelper {
 
     public final static void createCaseHandler(HttpServletRequest request, 
HttpServletResponse response,
         CaseHandler a) throws Throwable {
         ContextManager.createLocalSpan("For-Test");
-        
ContextManager.getRuntimeContext().put(Constants.REQUEST_KEY_IN_RUNTIME_CONTEXT,
 new JavaxServletRequestHolder(request));
-        
ContextManager.getRuntimeContext().put(Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT,
 new JavaxServletResponseHolder(response));
+        
ContextManager.getRuntimeContext().put(Constants.REQUEST_KEY_IN_RUNTIME_CONTEXT,
 request);
+        
ContextManager.getRuntimeContext().put(Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT,
 response);
         a.handleCase();
         ContextManager.stopSpan();
         
ContextManager.getRuntimeContext().remove(Constants.CONTROLLER_METHOD_STACK_DEPTH);
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/GetBeanInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/GetBeanInterceptor.java
index b2014c7..b063656 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/GetBeanInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/GetBeanInterceptor.java
@@ -22,8 +22,6 @@ 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;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.JavaxServletRequestHolder;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.JavaxServletResponseHolder;
 import org.springframework.web.context.request.NativeWebRequest;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
@@ -50,12 +48,12 @@ public class GetBeanInterceptor implements 
InstanceMethodsAroundInterceptor {
                 ContextManager.getRuntimeContext()
                               .put(
                                   REQUEST_KEY_IN_RUNTIME_CONTEXT,
-                                  new 
JavaxServletRequestHolder(requestAttributes.getRequest())
+                                  requestAttributes.getRequest()
                               );
                 ContextManager.getRuntimeContext()
                               .put(
                                   RESPONSE_KEY_IN_RUNTIME_CONTEXT,
-                                  new 
JavaxServletResponseHolder(requestAttributes.getResponse())
+                                  requestAttributes.getResponse()
                               );
             }
         }
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/InvokeInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/InvokeInterceptor.java
index 0b13d2d..50eb1ea 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/InvokeInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/InvokeInterceptor.java
@@ -17,48 +17,56 @@
 
 package org.apache.skywalking.apm.plugin.spring.mvc.v5;
 
-import java.lang.reflect.Method;
 import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.RuntimeContext;
 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.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.plugin.spring.mvc.commons.ReactiveRequestHolder;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.ReactiveResponseHolder;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext;
 import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpResponse;
 import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 
+import java.lang.reflect.Method;
+
+import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.REACTIVE_ASYNC_SPAN_IN_RUNTIME_CONTEXT;
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.REQUEST_KEY_IN_RUNTIME_CONTEXT;
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT;
 
-public class InvokeInterceptor implements InstanceMethodsAroundInterceptor {
+public class InvokeInterceptor implements InstanceMethodsAroundInterceptorV2 {
     @Override
-    public void beforeMethod(final EnhancedInstance objInst,
-                             final Method method,
-                             final Object[] allArguments,
-                             final Class<?>[] argumentsTypes,
-                             final MethodInterceptResult result) throws 
Throwable {
+    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] 
allArguments, Class<?>[] argumentsTypes, MethodInvocationContext context) 
throws Throwable {
         ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
-        final ReactiveResponseHolder responseHolder = new 
ReactiveResponseHolder(exchange.getResponse());
-        ContextManager.getRuntimeContext()
-                .put(RESPONSE_KEY_IN_RUNTIME_CONTEXT, responseHolder);
-        ContextManager.getRuntimeContext()
-                .put(REQUEST_KEY_IN_RUNTIME_CONTEXT, new 
ReactiveRequestHolder(exchange.getRequest()));
-        objInst.setSkyWalkingDynamicField(responseHolder);
+        final ServerHttpResponse response = exchange.getResponse();
+        /**
+         * First, we put the slot in the RuntimeContext,
+         * as well as the MethodInvocationContext (MIC),
+         * so that we can access it in the {@link 
org.apache.skywalking.apm.plugin.spring.mvc.v5.InvokeInterceptor#afterMethod}
+         * Then we fetch the slot from {@link 
org.apache.skywalking.apm.plugin.spring.mvc.commons.interceptor.AbstractMethodInterceptor#afterMethod}
+         * and fulfill the slot with the real AbstractSpan.
+         * Afterwards, we can safely remove the RuntimeContext.
+         * Finally, when the lambda executes in the {@link 
reactor.core.publisher.Mono#doFinally},
+         * ref of span could be acquired from MIC.
+         */
+        AbstractSpan[] ref = new AbstractSpan[1];
+        RuntimeContext runtimeContext = ContextManager.getRuntimeContext();
+        runtimeContext.put(REACTIVE_ASYNC_SPAN_IN_RUNTIME_CONTEXT, ref);
+        runtimeContext.put(RESPONSE_KEY_IN_RUNTIME_CONTEXT, response);
+        runtimeContext.put(REQUEST_KEY_IN_RUNTIME_CONTEXT, 
exchange.getRequest());
+        context.setContext(ref);
     }
 
     @Override
-    public Object afterMethod(final EnhancedInstance objInst,
-                              final Method method,
-                              final Object[] allArguments,
-                              final Class<?>[] argumentsTypes,
-                              final Object ret) throws Throwable {
+    public Object afterMethod(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes, Object ret, 
MethodInvocationContext context) throws Throwable {
         ServerWebExchange exchange = (ServerWebExchange) allArguments[0];
         return ((Mono) ret).doFinally(s -> {
-            ReactiveResponseHolder responseHolder = (ReactiveResponseHolder) 
objInst.getSkyWalkingDynamicField();
-            AbstractSpan span = responseHolder.getSpan();
+            Object ctx = context.getContext();
+            if (ctx == null) {
+                return;
+            }
+            AbstractSpan span = ((AbstractSpan[]) ctx)[0];
             if (span == null) {
                 return;
             }
@@ -72,11 +80,7 @@ public class InvokeInterceptor implements 
InstanceMethodsAroundInterceptor {
     }
 
     @Override
-    public void handleMethodException(final EnhancedInstance objInst,
-                                      final Method method,
-                                      final Object[] allArguments,
-                                      final Class<?>[] argumentsTypes,
-                                      final Throwable t) {
+    public void handleMethodException(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes, Throwable t, 
MethodInvocationContext context) {
 
     }
 }
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractSpring5Instrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractSpring5Instrumentation.java
index 1f1ee13..28d4de3 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractSpring5Instrumentation.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/AbstractSpring5Instrumentation.java
@@ -20,10 +20,10 @@ package 
org.apache.skywalking.apm.plugin.spring.mvc.v5.define;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
 
 public abstract class AbstractSpring5Instrumentation extends 
ClassInstanceMethodsEnhancePluginDefine {
-    public static final String WITHNESS_CLASSES = 
"org.springframework.web.servlet.resource.HttpResource";
+    public static final String WITNESS_CLASSES = 
"org.springframework.web.servlet.resource.HttpResource";
 
     @Override
     protected final String[] witnessClasses() {
-        return new String[] {WITHNESS_CLASSES};
+        return new String[] {WITNESS_CLASSES};
     }
 }
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentation.java
index 8d37b84..5753deb 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentation.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentation.java
@@ -20,10 +20,10 @@ package 
org.apache.skywalking.apm.plugin.spring.mvc.v5.define.reactive;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
 
 public abstract class AbstractSpring5ReactiveInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefine {
-    public static final String WITHNESS_CLASSES = 
"org.springframework.web.reactive.result.method.InvocableHandlerMethod";
+    public static final String WITNESS_CLASSES = 
"org.springframework.web.reactive.result.method.InvocableHandlerMethod";
 
     @Override
     protected final String[] witnessClasses() {
-        return new String[] {WITHNESS_CLASSES};
+        return new String[] {WITNESS_CLASSES};
     }
 }
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentationV2.java
similarity index 75%
copy from 
apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentation.java
copy to 
apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentationV2.java
index 8d37b84..52adbb7 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentation.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/AbstractSpring5ReactiveInstrumentationV2.java
@@ -17,13 +17,13 @@
 
 package org.apache.skywalking.apm.plugin.spring.mvc.v5.define.reactive;
 
-import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.ClassInstanceMethodsEnhancePluginDefineV2;
 
-public abstract class AbstractSpring5ReactiveInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefine {
-    public static final String WITHNESS_CLASSES = 
"org.springframework.web.reactive.result.method.InvocableHandlerMethod";
+public abstract class AbstractSpring5ReactiveInstrumentationV2 extends 
ClassInstanceMethodsEnhancePluginDefineV2 {
+    public static final String WITNESS_CLASSES = 
"org.springframework.web.reactive.result.method.InvocableHandlerMethod";
 
     @Override
     protected final String[] witnessClasses() {
-        return new String[] {WITHNESS_CLASSES};
+        return new String[] {WITNESS_CLASSES};
     }
 }
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/InvocableHandlerMethodInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/InvocableHandlerMethodInstrumentation.java
index 27884ed..b0a8bdb 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/InvocableHandlerMethodInstrumentation.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-5.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/v5/define/reactive/InvocableHandlerMethodInstrumentation.java
@@ -20,15 +20,14 @@ package 
org.apache.skywalking.apm.plugin.spring.mvc.v5.define.reactive;
 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.v2.InstanceMethodsInterceptV2Point;
 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 InvocableHandlerMethodInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefine {
+public class InvocableHandlerMethodInstrumentation extends 
AbstractSpring5ReactiveInstrumentationV2 {
     @Override
     protected ClassMatch enhanceClass() {
         return 
byName("org.springframework.web.reactive.result.method.InvocableHandlerMethod");
@@ -40,9 +39,9 @@ public class InvocableHandlerMethodInstrumentation extends 
ClassInstanceMethodsE
     }
 
     @Override
-    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() 
{
-        return new InstanceMethodsInterceptPoint[] {
-            new InstanceMethodsInterceptPoint() {
+    public InstanceMethodsInterceptV2Point[] 
getInstanceMethodsInterceptV2Points() {
+        return new InstanceMethodsInterceptV2Point[] {
+            new InstanceMethodsInterceptV2Point() {
                 @Override
                 public ElementMatcher<MethodDescription> getMethodsMatcher() {
                     return named("invoke").and(
@@ -50,7 +49,7 @@ public class InvocableHandlerMethodInstrumentation extends 
ClassInstanceMethodsE
                 }
 
                 @Override
-                public String getMethodsInterceptor() {
+                public String getMethodsInterceptorV2() {
                     return 
"org.apache.skywalking.apm.plugin.spring.mvc.v5.InvokeInterceptor";
                 }
 
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/Constants.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/Constants.java
index 6341b06..85a389f 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/Constants.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/Constants.java
@@ -34,6 +34,8 @@ public class Constants {
 
     public static final String RESPONSE_KEY_IN_RUNTIME_CONTEXT = "SW_RESPONSE";
 
+    public static final String REACTIVE_ASYNC_SPAN_IN_RUNTIME_CONTEXT = 
"SW_REACTIVE_RESPONSE_ASYNC_SPAN";
+
     public static final String FORWARD_REQUEST_FLAG = 
"SW_FORWARD_REQUEST_FLAG";
 
     public static final String WEBFLUX_REQUEST_KEY = "SW_WEBFLUX_REQUEST_KEY";
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/JavaxServletRequestHolder.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/JavaxServletRequestHolder.java
deleted file mode 100644
index 8eb5705..0000000
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/JavaxServletRequestHolder.java
+++ /dev/null
@@ -1,56 +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;
-import javax.servlet.http.HttpServletRequest;
-
-public class JavaxServletRequestHolder implements RequestHolder {
-
-    private final HttpServletRequest request;
-
-    public JavaxServletRequestHolder(HttpServletRequest request) {
-        this.request = request;
-    }
-
-    @Override
-    public String getHeader(final String headerName) {
-        return request.getHeader(headerName);
-    }
-
-    @Override
-    public Enumeration<String> getHeaders(final String headerName) {
-        return request.getHeaders(headerName);
-    }
-
-    @Override
-    public String requestURL() {
-        return request.getRequestURL().toString();
-    }
-
-    @Override
-    public String requestMethod() {
-        return request.getMethod();
-    }
-
-    @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/ReactiveRequestHolder.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/ReactiveRequestHolder.java
deleted file mode 100644
index b5e1876..0000000
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/ReactiveRequestHolder.java
+++ /dev/null
@@ -1,66 +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.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-
-public class ReactiveRequestHolder implements RequestHolder {
-    private final ServerHttpRequest serverHttpRequest;
-
-    public ReactiveRequestHolder(final ServerHttpRequest serverHttpRequest) {
-        this.serverHttpRequest = serverHttpRequest;
-    }
-
-    @Override
-    public String getHeader(final String headerName) {
-        return this.serverHttpRequest.getHeaders().getFirst(headerName);
-    }
-
-    @Override
-    public Enumeration<String> getHeaders(final String headerName) {
-        List<String> values = 
this.serverHttpRequest.getHeaders().get(headerName);
-        if (values == null) {
-            return Collections.enumeration(Collections.EMPTY_LIST);
-        }
-        return Collections.enumeration(values);
-    }
-
-    @Override
-    public String requestURL() {
-        return this.serverHttpRequest.getURI().toString();
-    }
-
-    @Override
-    public String requestMethod() {
-        return this.serverHttpRequest.getMethodValue();
-    }
-
-    @Override
-    public Map<String, String[]> getParameterMap() {
-        Map<String, String[]> parameterMap = new 
HashMap<>(this.serverHttpRequest.getQueryParams().size());
-        this.serverHttpRequest.getQueryParams().forEach((key, value) -> {
-            parameterMap.put(key, value.toArray(new String[0]));
-        });
-        return parameterMap;
-    }
-}
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/ReactiveResponseHolder.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/ReactiveResponseHolder.java
deleted file mode 100644
index 995114c..0000000
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/ReactiveResponseHolder.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.spring.mvc.commons;
-
-import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
-import org.springframework.http.server.reactive.ServerHttpResponse;
-
-public class ReactiveResponseHolder implements ResponseHolder {
-
-    private final ServerHttpResponse response;
-
-    private AbstractSpan span;
-
-    public ReactiveResponseHolder(final ServerHttpResponse response) {
-        this.response = response;
-    }
-
-    public void setSpan(AbstractSpan span) {
-        this.span = span;
-    }
-
-    public AbstractSpan getSpan() {
-        return this.span;
-    }
-
-    @Override
-    public int statusCode() {
-        return response.getStatusCode().value();
-    }
-}
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
new file mode 100644
index 0000000..640e04c
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestUtil.java
@@ -0,0 +1,110 @@
+/*
+ *  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 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.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;
+import java.util.HashMap;
+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(ServerHttpRequest request, 
AbstractSpan span) {
+        Map<String, String[]> parameterMap = new 
HashMap<>(request.getQueryParams().size());
+        request.getQueryParams().forEach((key, value) -> {
+            parameterMap.put(key, value.toArray(new String[0]));
+        });
+        if (!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 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(ServerHttpRequest 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 -> getHeaders(request, 
headerName).hasMoreElements())
+                .forEach(headerName -> {
+                    Enumeration<String> headerValues = getHeaders(request, 
headerName);
+                    List<String> valueList = Collections.list(
+                            headerValues);
+                    if (!CollectionUtil.isEmpty(valueList)) {
+                        String headerValue = valueList.toString();
+                        headersList.add(headerName + "=" + headerValue);
+                    }
+                });
+
+        collectHttpHeaders(headersList, span);
+    }
+
+    private static void collectHttpHeaders(final List<String> headersList, 
final AbstractSpan span) {
+        if (headersList != null && !headersList.isEmpty()) {
+            String tagValue = String.join("\n", headersList);
+            tagValue = 
SpringMVCPluginConfig.Plugin.Http.HTTP_HEADERS_LENGTH_THRESHOLD > 0 ?
+                    StringUtil.cut(tagValue, 
SpringMVCPluginConfig.Plugin.Http.HTTP_HEADERS_LENGTH_THRESHOLD) : tagValue;
+            Tags.HTTP.HEADERS.set(span, tagValue);
+        }
+    }
+
+    public static Enumeration<String> getHeaders(final ServerHttpRequest 
request, final String headerName) {
+        List<String> values = request.getHeaders().get(headerName);
+        if (values == null) {
+            return Collections.enumeration(Collections.emptyList());
+        }
+        return Collections.enumeration(values);
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/ResponseHolder.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/ResponseHolder.java
deleted file mode 100644
index b46c4f2..0000000
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/ResponseHolder.java
+++ /dev/null
@@ -1,22 +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;
-
-public interface ResponseHolder {
-    int statusCode();
-}
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 bcfcb6d..c6121a6 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
@@ -18,16 +18,10 @@
 
 package org.apache.skywalking.apm.plugin.spring.mvc.commons.interceptor;
 
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
 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.RuntimeContext;
 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;
@@ -38,16 +32,20 @@ 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.spring.mvc.commons.EnhanceRequireObjectCache;
-import org.apache.skywalking.apm.plugin.spring.mvc.commons.RequestHolder;
-import org.apache.skywalking.apm.plugin.spring.mvc.commons.ResponseHolder;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.ReactiveResponseHolder;
+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;
 import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.exception.ServletResponseNotFoundException;
-import org.apache.skywalking.apm.util.StringUtil;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.lang.reflect.Method;
 
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.CONTROLLER_METHOD_STACK_DEPTH;
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.FORWARD_REQUEST_FLAG;
+import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.REACTIVE_ASYNC_SPAN_IN_RUNTIME_CONTEXT;
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.REQUEST_KEY_IN_RUNTIME_CONTEXT;
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT;
 
@@ -60,9 +58,17 @@ public abstract class AbstractMethodInterceptor implements 
InstanceMethodsAround
     private static final String SERVLET_RESPONSE_CLASS = 
"javax.servlet.http.HttpServletResponse";
     private static final String GET_STATUS_METHOD = "getStatus";
 
+    private static boolean IN_SERVLET_CONTAINER;
+
     static {
         IS_SERVLET_GET_STATUS_METHOD_EXIST = MethodUtil.isMethodExist(
-            AbstractMethodInterceptor.class.getClassLoader(), 
SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD);
+                AbstractMethodInterceptor.class.getClassLoader(), 
SERVLET_RESPONSE_CLASS, GET_STATUS_METHOD);
+        try {
+            Class.forName(SERVLET_RESPONSE_CLASS, true, 
AbstractMethodInterceptor.class.getClassLoader());
+            IN_SERVLET_CONTAINER = true;
+        } catch (Exception ignore) {
+            IN_SERVLET_CONTAINER = false;
+        }
     }
 
     public abstract String getRequestURL(Method method);
@@ -96,31 +102,58 @@ public abstract class AbstractMethodInterceptor implements 
InstanceMethodsAround
             operationName = getAcceptedMethodTypes(method) + requestURL;
         }
 
-        RequestHolder request = (RequestHolder) 
ContextManager.getRuntimeContext()
-                                                              
.get(REQUEST_KEY_IN_RUNTIME_CONTEXT);
+        Object request = 
ContextManager.getRuntimeContext().get(REQUEST_KEY_IN_RUNTIME_CONTEXT);
+
         if (request != null) {
             StackDepth stackDepth = (StackDepth) 
ContextManager.getRuntimeContext().get(CONTROLLER_METHOD_STACK_DEPTH);
 
             if (stackDepth == null) {
-                ContextCarrier contextCarrier = new ContextCarrier();
-                CarrierItem next = contextCarrier.items();
-                while (next.hasNext()) {
-                    next = next.next();
-                    next.setHeadValue(request.getHeader(next.getHeadKey()));
-                }
-
-                AbstractSpan span = 
ContextManager.createEntrySpan(operationName, contextCarrier);
-                Tags.URL.set(span, request.requestURL());
-                Tags.HTTP.METHOD.set(span, request.requestMethod());
-                span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
-                SpanLayer.asHttp(span);
-
-                if 
(SpringMVCPluginConfig.Plugin.SpringMVC.COLLECT_HTTP_PARAMS) {
-                    collectHttpParam(request, span);
-                }
-
-                if 
(!CollectionUtil.isEmpty(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS))
 {
-                    collectHttpHeaders(request, span);
+                final ContextCarrier contextCarrier = new ContextCarrier();
+
+                if (IN_SERVLET_CONTAINER && 
HttpServletRequest.class.isAssignableFrom(request.getClass())) {
+                    final HttpServletRequest httpServletRequest = 
(HttpServletRequest) request;
+                    CarrierItem next = contextCarrier.items();
+                    while (next.hasNext()) {
+                        next = next.next();
+                        
next.setHeadValue(httpServletRequest.getHeader(next.getHeadKey()));
+                    }
+
+                    AbstractSpan span = 
ContextManager.createEntrySpan(operationName, contextCarrier);
+                    Tags.URL.set(span, 
httpServletRequest.getRequestURL().toString());
+                    Tags.HTTP.METHOD.set(span, httpServletRequest.getMethod());
+                    span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
+                    SpanLayer.asHttp(span);
+
+                    if 
(SpringMVCPluginConfig.Plugin.SpringMVC.COLLECT_HTTP_PARAMS) {
+                        RequestUtil.collectHttpParam(httpServletRequest, span);
+                    }
+
+                    if 
(!CollectionUtil.isEmpty(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS))
 {
+                        RequestUtil.collectHttpHeaders(httpServletRequest, 
span);
+                    }
+                } else if 
(ServerHttpRequest.class.isAssignableFrom(request.getClass())) {
+                    final ServerHttpRequest serverHttpRequest = 
(ServerHttpRequest) request;
+                    CarrierItem next = contextCarrier.items();
+                    while (next.hasNext()) {
+                        next = next.next();
+                        
next.setHeadValue(serverHttpRequest.getHeaders().getFirst(next.getHeadKey()));
+                    }
+
+                    AbstractSpan span = 
ContextManager.createEntrySpan(operationName, contextCarrier);
+                    Tags.URL.set(span, serverHttpRequest.getURI().toString());
+                    Tags.HTTP.METHOD.set(span, 
serverHttpRequest.getMethodValue());
+                    span.setComponent(ComponentsDefine.SPRING_MVC_ANNOTATION);
+                    SpanLayer.asHttp(span);
+
+                    if 
(SpringMVCPluginConfig.Plugin.SpringMVC.COLLECT_HTTP_PARAMS) {
+                        RequestUtil.collectHttpParam(serverHttpRequest, span);
+                    }
+
+                    if 
(!CollectionUtil.isEmpty(SpringMVCPluginConfig.Plugin.Http.INCLUDE_HTTP_HEADERS))
 {
+                        RequestUtil.collectHttpHeaders(serverHttpRequest, 
span);
+                    }
+                } else {
+                    throw new IllegalStateException("this line should not be 
reached");
                 }
 
                 stackDepth = new StackDepth();
@@ -136,8 +169,8 @@ public abstract class AbstractMethodInterceptor implements 
InstanceMethodsAround
 
     private String buildOperationName(Object invoker, Method method) {
         StringBuilder operationName = new 
StringBuilder(invoker.getClass().getName()).append(".")
-                                                                               
      .append(method.getName())
-                                                                               
      .append("(");
+                .append(method.getName())
+                .append("(");
         for (Class<?> type : method.getParameterTypes()) {
             operationName.append(type.getName()).append(",");
         }
@@ -152,7 +185,8 @@ public abstract class AbstractMethodInterceptor implements 
InstanceMethodsAround
     @Override
     public Object afterMethod(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes,
                               Object ret) throws Throwable {
-        Boolean forwardRequestFlag = (Boolean) 
ContextManager.getRuntimeContext().get(FORWARD_REQUEST_FLAG);
+        final RuntimeContext runtimeContext = 
ContextManager.getRuntimeContext();
+        Boolean forwardRequestFlag = (Boolean) 
runtimeContext.get(FORWARD_REQUEST_FLAG);
         /**
          * Spring MVC plugin do nothing if current request is forward request.
          * Ref: https://github.com/apache/skywalking/pull/1325
@@ -161,11 +195,10 @@ public abstract class AbstractMethodInterceptor 
implements InstanceMethodsAround
             return ret;
         }
 
-        RequestHolder request = (RequestHolder) 
ContextManager.getRuntimeContext()
-                                                              
.get(REQUEST_KEY_IN_RUNTIME_CONTEXT);
+        Object request = runtimeContext.get(REQUEST_KEY_IN_RUNTIME_CONTEXT);
 
         if (request != null) {
-            StackDepth stackDepth = (StackDepth) 
ContextManager.getRuntimeContext().get(CONTROLLER_METHOD_STACK_DEPTH);
+            StackDepth stackDepth = (StackDepth) 
runtimeContext.get(CONTROLLER_METHOD_STACK_DEPTH);
             if (stackDepth == null) {
                 throw new IllegalMethodStackDepthException();
             } else {
@@ -175,30 +208,43 @@ public abstract class AbstractMethodInterceptor 
implements InstanceMethodsAround
             AbstractSpan span = ContextManager.activeSpan();
 
             if (stackDepth.depth() == 0) {
-                ResponseHolder response = (ResponseHolder) 
ContextManager.getRuntimeContext()
-                                                                         .get(
-                                                                             
RESPONSE_KEY_IN_RUNTIME_CONTEXT);
+                Object response = 
runtimeContext.get(RESPONSE_KEY_IN_RUNTIME_CONTEXT);
                 if (response == null) {
                     throw new ServletResponseNotFoundException();
                 }
 
-                if (IS_SERVLET_GET_STATUS_METHOD_EXIST && 
response.statusCode() >= 400) {
-                    span.errorOccurred();
-                    Tags.STATUS_CODE.set(span, 
Integer.toString(response.statusCode()));
+                Integer statusCode = null;
+
+                if (IS_SERVLET_GET_STATUS_METHOD_EXIST && 
HttpServletResponse.class.isAssignableFrom(response.getClass())) {
+                    statusCode = ((HttpServletResponse) response).getStatus();
+                } else if 
(ServerHttpResponse.class.isAssignableFrom(response.getClass())) {
+                    if (IS_SERVLET_GET_STATUS_METHOD_EXIST) {
+                        statusCode = ((ServerHttpResponse) 
response).getRawStatusCode();
+                    }
+                    Object context = 
runtimeContext.get(REACTIVE_ASYNC_SPAN_IN_RUNTIME_CONTEXT);
+                    if (context != null) {
+                        ((AbstractSpan[]) context)[0] = span.prepareForAsync();
+                    }
                 }
-                if (response instanceof ReactiveResponseHolder) {
-                    ReactiveResponseHolder reactiveResponse = 
(ReactiveResponseHolder) response;
-                    AbstractSpan async = span.prepareForAsync();
-                    reactiveResponse.setSpan(async);
+
+                if (statusCode != null && statusCode >= 400) {
+                    span.errorOccurred();
+                    Tags.STATUS_CODE.set(span, Integer.toString(statusCode));
                 }
-                
ContextManager.getRuntimeContext().remove(REQUEST_KEY_IN_RUNTIME_CONTEXT);
-                
ContextManager.getRuntimeContext().remove(RESPONSE_KEY_IN_RUNTIME_CONTEXT);
-                
ContextManager.getRuntimeContext().remove(CONTROLLER_METHOD_STACK_DEPTH);
+
+                runtimeContext.remove(REACTIVE_ASYNC_SPAN_IN_RUNTIME_CONTEXT);
+                runtimeContext.remove(REQUEST_KEY_IN_RUNTIME_CONTEXT);
+                runtimeContext.remove(RESPONSE_KEY_IN_RUNTIME_CONTEXT);
+                runtimeContext.remove(CONTROLLER_METHOD_STACK_DEPTH);
             }
 
             // Active HTTP parameter collection automatically in the profiling 
context.
             if (!SpringMVCPluginConfig.Plugin.SpringMVC.COLLECT_HTTP_PARAMS && 
span.isProfiling()) {
-                collectHttpParam(request, span);
+                if 
(HttpServletRequest.class.isAssignableFrom(request.getClass())) {
+                    RequestUtil.collectHttpParam((HttpServletRequest) request, 
span);
+                } else if 
(ServerHttpRequest.class.isAssignableFrom(request.getClass())) {
+                    RequestUtil.collectHttpParam((ServerHttpRequest) request, 
span);
+                }
             }
 
             ContextManager.stopSpan();
@@ -212,38 +258,4 @@ public abstract class AbstractMethodInterceptor implements 
InstanceMethodsAround
                                       Class<?>[] argumentsTypes, Throwable t) {
         ContextManager.activeSpan().log(t);
     }
-
-    private void collectHttpParam(RequestHolder 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);
-        }
-    }
-
-    private void collectHttpHeaders(RequestHolder 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);
-                                                                  }
-                                                              });
-
-        if (!headersList.isEmpty()) {
-            String tagValue = 
headersList.stream().collect(Collectors.joining("\n"));
-            tagValue = 
SpringMVCPluginConfig.Plugin.Http.HTTP_HEADERS_LENGTH_THRESHOLD > 0 ?
-                StringUtil.cut(tagValue, 
SpringMVCPluginConfig.Plugin.Http.HTTP_HEADERS_LENGTH_THRESHOLD) : tagValue;
-            Tags.HTTP.HEADERS.set(span, tagValue);
-        }
-    }
 }
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/GetBeanInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/GetBeanInterceptor.java
index 3fd2d61..6cc6c62 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/GetBeanInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/GetBeanInterceptor.java
@@ -23,7 +23,6 @@ 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;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.JavaxServletRequestHolder;
 import org.springframework.web.context.request.NativeWebRequest;
 import org.springframework.web.context.request.RequestContextHolder;
 import org.springframework.web.context.request.ServletRequestAttributes;
@@ -45,8 +44,8 @@ public class GetBeanInterceptor implements 
InstanceMethodsAroundInterceptor {
         Object ret) throws Throwable {
         if (ret instanceof EnhancedInstance) {
             ContextManager.getRuntimeContext()
-                          .put(REQUEST_KEY_IN_RUNTIME_CONTEXT, new 
JavaxServletRequestHolder(((ServletRequestAttributes) 
RequestContextHolder.getRequestAttributes())
-                              .getRequest()));
+                          .put(REQUEST_KEY_IN_RUNTIME_CONTEXT, 
((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())
+                              .getRequest());
         }
         return ret;
     }
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/InvokeForRequestInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/InvokeForRequestInterceptor.java
index 4360048..9d9b915 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/InvokeForRequestInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/InvokeForRequestInterceptor.java
@@ -19,12 +19,10 @@
 package org.apache.skywalking.apm.plugin.spring.mvc.commons.interceptor;
 
 import java.lang.reflect.Method;
-import javax.servlet.http.HttpServletResponse;
 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;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.JavaxServletResponseHolder;
 import org.springframework.web.context.request.NativeWebRequest;
 
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT;
@@ -38,8 +36,7 @@ public class InvokeForRequestInterceptor implements 
InstanceMethodsAroundInterce
     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] 
allArguments, Class<?>[] argumentsTypes,
                              MethodInterceptResult result) throws Throwable {
         ContextManager.getRuntimeContext()
-                      .put(RESPONSE_KEY_IN_RUNTIME_CONTEXT, new 
JavaxServletResponseHolder(
-                          (HttpServletResponse) ((NativeWebRequest) 
allArguments[0]).getNativeResponse()));
+                .put(RESPONSE_KEY_IN_RUNTIME_CONTEXT, ((NativeWebRequest) 
allArguments[0]).getNativeResponse());
     }
 
     @Override
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/InvokeHandlerMethodInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/InvokeHandlerMethodInterceptor.java
index 9d7df03..bc6e2f9 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/InvokeHandlerMethodInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/interceptor/InvokeHandlerMethodInterceptor.java
@@ -18,15 +18,12 @@
 
 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.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;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.JavaxServletRequestHolder;
-import 
org.apache.skywalking.apm.plugin.spring.mvc.commons.JavaxServletResponseHolder;
+
+import java.lang.reflect.Method;
 
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.REQUEST_KEY_IN_RUNTIME_CONTEXT;
 import static 
org.apache.skywalking.apm.plugin.spring.mvc.commons.Constants.RESPONSE_KEY_IN_RUNTIME_CONTEXT;
@@ -36,10 +33,8 @@ public class InvokeHandlerMethodInterceptor implements 
InstanceMethodsAroundInte
     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] 
allArguments, Class<?>[] argumentsTypes,
                              MethodInterceptResult result) throws Throwable {
         if (allArguments[2] instanceof EnhancedInstance) {
-            
ContextManager.getRuntimeContext().put(RESPONSE_KEY_IN_RUNTIME_CONTEXT, new 
JavaxServletResponseHolder(
-                (HttpServletResponse) allArguments[1]));
-            
ContextManager.getRuntimeContext().put(REQUEST_KEY_IN_RUNTIME_CONTEXT, new 
JavaxServletRequestHolder(
-                (HttpServletRequest) allArguments[0]));
+            
ContextManager.getRuntimeContext().put(RESPONSE_KEY_IN_RUNTIME_CONTEXT, 
allArguments[1]);
+            
ContextManager.getRuntimeContext().put(REQUEST_KEY_IN_RUNTIME_CONTEXT, 
allArguments[0]);
         }
     }
 
diff --git 
a/test/plugin/scenarios/springmvc-reactive-devtools-scenario/bin/startup.sh 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/bin/startup.sh
new file mode 100644
index 0000000..db12139
--- /dev/null
+++ b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/bin/startup.sh
@@ -0,0 +1,24 @@
+#!/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
+# 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.
+
+set -ex
+
+home="$(cd "$(dirname $0)"; pwd)"
+
+classpath="$(printf %s: 
$home/../target/3rd-lib/*.jar)${home}/../target/classes"
+java ${agent_opts} -classpath "$classpath" 
test.apache.skywalking.apm.testcase.sc.springmvcreactive.Application &
diff --git 
a/test/plugin/scenarios/springmvc-reactive-devtools-scenario/config/expectedData.yaml
 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/config/expectedData.yaml
new file mode 100644
index 0000000..95dd650
--- /dev/null
+++ 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/config/expectedData.yaml
@@ -0,0 +1,103 @@
+# 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.
+
+segmentItems:
+- serviceName: springmvc-reactive-devtools-scenario
+  segmentSize: ge 2
+  segments:
+  - segmentId: not null
+    spans:
+    - operationName: H2/JDBI/PreparedStatement/executeQuery
+      operationId: 0
+      parentSpanId: 0
+      spanId: 1
+      spanLayer: Database
+      startTime: not null
+      endTime: not null
+      componentId: 32
+      isError: false
+      spanType: Exit
+      peer: not null
+      tags:
+      - {key: db.type, value: not null}
+      - {key: db.instance, value: test}
+      - {key: db.statement, value: not null}
+      skipAnalysis: 'false'
+    - operationName: '/testcase/error'
+      operationId: 0
+      parentSpanId: 0
+      spanId: 2
+      spanLayer: Http
+      startTime: not null
+      endTime: not null
+      isError: false
+      componentId: not null
+      tags:
+      - {key: url, value: not null}
+      - {key: http.method, value: GET}
+      skipAnalysis: 'false'
+    - operationName: 'future/get:/testcase/error'
+      operationId: 0
+      parentSpanId: 0
+      spanId: 3
+      spanLayer: not null
+      startTime: not null
+      endTime: not null
+      isError: true
+      componentId: not null
+      logs:
+      - logEvent:
+        - {key: event, value: error}
+        - {key: error.kind, value: not null}
+        - {key: message, value: not null}
+        - {key: stack, value: not null}
+      skipAnalysis: 'false'
+    - operationName: '{GET}/testcase/{test}'
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: Http
+      startTime: not null
+      endTime: not null
+      componentId: 14
+      isError: false
+      tags:
+      - {key: url, value: not null}
+      - {key: http.method, value: GET}
+      skipAnalysis: 'false'
+  - segmentId: not null
+    spans:
+    - operationName: '{GET}/testcase/error'
+      operationId: 0
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: Http
+      startTime: not null
+      endTime: not null
+      componentId: 14
+      spanType: Entry
+      isError: true
+      tags:
+      - {key: url, value: not null}
+      - {key: http.method, value: GET}
+      - {key: status_code, value: '500'}
+      logs:
+      - logEvent:
+        - {key: event, value: error}
+        - {key: error.kind, value: not null}
+        - {key: message, value: not null}
+        - {key: stack, value: not null}
+      skipAnalysis: 'false'
\ No newline at end of file
diff --git 
a/test/plugin/scenarios/springmvc-reactive-devtools-scenario/configuration.yml 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/configuration.yml
new file mode 100644
index 0000000..12cb454
--- /dev/null
+++ 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/configuration.yml
@@ -0,0 +1,20 @@
+# 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.
+
+type: jvm
+entryService: http://localhost:8080/testcase/test
+healthCheck: http://localhost:8080/testcase/healthCheck
+startScript: ./bin/startup.sh
diff --git a/test/plugin/scenarios/springmvc-reactive-scenario/pom.xml 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/pom.xml
similarity index 71%
copy from test/plugin/scenarios/springmvc-reactive-scenario/pom.xml
copy to test/plugin/scenarios/springmvc-reactive-devtools-scenario/pom.xml
index aa3c075..05badf7 100644
--- a/test/plugin/scenarios/springmvc-reactive-scenario/pom.xml
+++ b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/pom.xml
@@ -22,11 +22,11 @@
     <modelVersion>4.0.0</modelVersion>
 
     <groupId>org.apache.skywalking</groupId>
-    <artifactId>springmvc-reactive-scenario</artifactId>
+    <artifactId>springmvc-reactive-devtools-scenario</artifactId>
     <packaging>jar</packaging>
     <version>5.0.0</version>
 
-    <name>skywalking-springmvc-reactive-scenario</name>
+    <name>skywalking-springmvc-reactive-devtools-scenario</name>
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@@ -41,6 +41,12 @@
             <version>${test.framework.version}</version>
         </dependency>
         <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional>
+            <version>${test.framework.version}</version>
+        </dependency>
+        <dependency>
             <groupId>com.h2database</groupId>
             <artifactId>h2</artifactId>
             <version>1.4.200</version>
@@ -48,10 +54,31 @@
     </dependencies>
 
     <build>
-        <finalName>springmvc-reactive-scenario</finalName>
+        <finalName>springmvc-reactive-devtools-scenario</finalName>
         <plugins>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-dependencies</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <type>jar</type>
+                            <includeTypes>jar</includeTypes>
+                            <includeScope>runtime</includeScope>
+                            <outputDirectory>
+                                ${project.build.directory}/3rd-lib/
+                            </outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
                 <version>3.6.0</version>
                 <configuration>
@@ -63,7 +90,7 @@
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
-                <version>1.5.9.RELEASE</version>
+                <version>${test.framework.version}</version>
                 <executions>
                     <execution>
                         <goals>
diff --git 
a/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/assembly/assembly.xml
 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/assembly/assembly.xml
new file mode 100644
index 0000000..5e8d436
--- /dev/null
+++ 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/assembly/assembly.xml
@@ -0,0 +1,49 @@
+<?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.
+  ~
+  -->
+<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>
+
+    <fileSets>
+        <fileSet>
+            <directory>./bin</directory>
+            <fileMode>0775</fileMode>
+        </fileSet>
+        <fileSet>
+            <directory>${project.build.directory}/classes</directory>
+            <fileMode>0775</fileMode>
+        </fileSet>
+        <fileSet>
+            <directory>${project.build.directory}/3rd-lib</directory>
+            <fileMode>0775</fileMode>
+        </fileSet>
+    </fileSets>
+
+    <files>
+        <file>
+            
<source>${project.build.directory}/springmvc-reactive-devtools-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/RequestHolder.java
 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/springmvcreactive/Application.java
similarity index 70%
rename from 
apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestHolder.java
rename to 
test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/springmvcreactive/Application.java
index 8f4c933..4d6eae3 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/RequestHolder.java
+++ 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/springmvcreactive/Application.java
@@ -15,19 +15,15 @@
  *  limitations under the License.
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.sc.springmvcreactive;
 
-import java.util.Enumeration;
-import java.util.Map;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
 
-public interface RequestHolder {
-    String getHeader(String headerName);
+@SpringBootApplication
+public class Application {
 
-    Enumeration<String> getHeaders(String headerName);
-
-    String requestURL();
-
-    String requestMethod();
-
-    Map<String, String[]> getParameterMap();
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
 }
diff --git 
a/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/springmvcreactive/controller/Controller.java
 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/springmvcreactive/controller/Controller.java
new file mode 100644
index 0000000..0117cad
--- /dev/null
+++ 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/springmvcreactive/controller/Controller.java
@@ -0,0 +1,60 @@
+/*
+ *  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.sc.springmvcreactive.controller;
+
+import java.sql.SQLException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.ResponseEntity;
+import org.springframework.util.concurrent.ListenableFuture;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.client.AsyncRestTemplate;
+import reactor.core.publisher.Mono;
+import 
test.apache.skywalking.apm.testcase.sc.springmvcreactive.service.TestService;
+
+@RestController
+public class Controller {
+
+    @Autowired
+    private TestService testService;
+
+    @RequestMapping("/testcase/healthCheck")
+    public String healthCheck() {
+        return "healthCheck";
+    }
+
+    @GetMapping("/testcase/{test}")
+    public Mono<String> hello(@RequestBody(required = false) String body, 
@PathVariable("test") String test) throws SQLException {
+        testService.executeSQL();
+        ListenableFuture<ResponseEntity<String>> forEntity = new 
AsyncRestTemplate().getForEntity("http://localhost:8080/testcase/error";, 
String.class);
+        try {
+            forEntity.get();
+        } catch (Exception e) {
+        }
+        return Mono.just("Hello World");
+    }
+
+    @GetMapping("/testcase/error")
+    public Mono<String> error() {
+        throw new RuntimeException("this is Error");
+    }
+
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/JavaxServletResponseHolder.java
 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/springmvcreactive/service/TestService.java
similarity index 54%
rename from 
apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/JavaxServletResponseHolder.java
rename to 
test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/springmvcreactive/service/TestService.java
index 7fc0144..aff108f 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/mvc-annotation-commons/src/main/java/org/apache/skywalking/apm/plugin/spring/mvc/commons/JavaxServletResponseHolder.java
+++ 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/springmvcreactive/service/TestService.java
@@ -15,21 +15,28 @@
  *  limitations under the License.
  */
 
-package org.apache.skywalking.apm.plugin.spring.mvc.commons;
+package test.apache.skywalking.apm.testcase.sc.springmvcreactive.service;
 
-import javax.servlet.http.HttpServletResponse;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import javax.annotation.PostConstruct;
+import org.springframework.stereotype.Service;
 
-public class JavaxServletResponseHolder implements ResponseHolder {
+@Service
+public class TestService {
 
-    private final HttpServletResponse response;
+    private Connection connection;
 
-    public JavaxServletResponseHolder(final HttpServletResponse response) {
-        this.response = response;
+    @PostConstruct
+    private void setUp() throws SQLException {
+        connection = 
DriverManager.getConnection("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1", "sa", "");
     }
 
-    @Override
-    public int statusCode() {
-        return response.getStatus();
+    public void executeSQL() throws SQLException {
+        PreparedStatement preparedStatement = 
connection.prepareStatement("SELECT 1 = 1");
+        preparedStatement.executeQuery();
     }
 
 }
diff --git 
a/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/resources/application.yml
 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/resources/application.yml
new file mode 100644
index 0000000..e916bcd
--- /dev/null
+++ 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/src/main/resources/application.yml
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+server.port: 8080
\ No newline at end of file
diff --git 
a/test/plugin/scenarios/springmvc-reactive-devtools-scenario/support-version.list
 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/support-version.list
new file mode 100644
index 0000000..c5820da
--- /dev/null
+++ 
b/test/plugin/scenarios/springmvc-reactive-devtools-scenario/support-version.list
@@ -0,0 +1,20 @@
+# 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.
+
+# 2.0.0-2.1.0 are supported, but due to the status code 
bug(https://github.com/spring-projects/spring-framework/issues/21901)
+# we don’t test them
+
+2.1.7.RELEASE
diff --git a/test/plugin/scenarios/springmvc-reactive-scenario/pom.xml 
b/test/plugin/scenarios/springmvc-reactive-scenario/pom.xml
index aa3c075..9459d98 100644
--- a/test/plugin/scenarios/springmvc-reactive-scenario/pom.xml
+++ b/test/plugin/scenarios/springmvc-reactive-scenario/pom.xml
@@ -63,7 +63,7 @@
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
-                <version>1.5.9.RELEASE</version>
+                <version>${test.framework.version}</version>
                 <executions>
                     <execution>
                         <goals>

Reply via email to