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

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


The following commit(s) were added to refs/heads/main by this push:
     new d5b99f9434 add support for HttpExchange along with 
webflux-webclient-6.x (#664)
d5b99f9434 is described below

commit d5b99f9434530403569cba3a1d0fbd74e07448c9
Author: Chen Ziyan <[email protected]>
AuthorDate: Thu Jan 11 19:58:42 2024 +0800

    add support for HttpExchange along with webflux-webclient-6.x (#664)
---
 .github/workflows/plugins-jdk17-test.1.yaml        |   1 +
 CHANGES.md                                         |   1 +
 apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml  |   1 +
 .../define/WebFluxWebClientInstrumentation.java    |  11 ++
 .../pom.xml                                        |  42 ++----
 .../webclient/BodyInserterRequestInterceptor.java  |  54 ++++++++
 .../v6/webclient/WebFluxWebClientInterceptor.java  | 126 +++++++++++++++++
 .../define/BodyInserterRequestInstrumentation.java |  67 +++++++++
 .../define/WebFluxWebClientInstrumentation.java    |  44 +++---
 .../src/main/resources/skywalking-plugin.def       |  18 +++
 .../setup/service-agent/java-agent/Plugin-list.md  |   1 +
 .../service-agent/java-agent/Supported-list.md     |   1 +
 .../httpexchange-scenario/config/expectedData.yaml | 150 +++++++++++++++++++++
 .../httpexchange-scenario/configuration.yml        |  20 +++
 .../httpexchange-dist/bin/startup.sh               |  24 ++++
 .../httpexchange-dist/pom.xml                      |  54 ++++++++
 .../src/main/assembly/assembly.xml                 |  46 +++++++
 .../httpexchange-projectA-scenario/pom.xml         |  62 +++++++++
 .../httpexchange/projectA/PorjectaApplication.java |  29 ++++
 .../httpexchange/projectA/api/TestcaseClient.java  |  43 ++++++
 .../projectA/config/RestClientConfig.java          |  43 ++++++
 .../projectA/controller/TestController.java        |  51 +++++++
 .../src/main/resources/application.yml             |  23 ++++
 .../httpexchange-projectB-scenario/pom.xml         |  57 ++++++++
 .../httpexchange/projectB/ProjectbApplication.java |  29 ++++
 .../controller/TestAnnotationController.java       |  50 +++++++
 .../src/main/resources/application.yml             |  19 +++
 .../plugin/scenarios/httpexchange-scenario/pom.xml |  59 ++++++++
 .../httpexchange-scenario/support-version.list     |  18 +++
 29 files changed, 1098 insertions(+), 46 deletions(-)

diff --git a/.github/workflows/plugins-jdk17-test.1.yaml 
b/.github/workflows/plugins-jdk17-test.1.yaml
index 09e2092791..21449a7861 100644
--- a/.github/workflows/plugins-jdk17-test.1.yaml
+++ b/.github/workflows/plugins-jdk17-test.1.yaml
@@ -58,6 +58,7 @@ jobs:
           - spring-6.x-scenario
           - resteasy-6.x-scenario
           - gateway-4.x-scenario
+          - httpexchange-scenario
     steps:
       - uses: actions/checkout@v2
         with:
diff --git a/CHANGES.md b/CHANGES.md
index 698de108df..5225574210 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -10,6 +10,7 @@ Release Notes.
 * Support for tracing spring-cloud-gateway 4.x in gateway-4.x-plugin.
 * Fix re-transform bug when plugin enhanced class proxy parent method.
 * Fix error HTTP status codes not recording as SLA failures in Vert.x plugins. 
+* Support for HttpExchange request tracing
 
 #### Documentation
 
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
index 95f7ff91fa..d9a61849aa 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
@@ -43,6 +43,7 @@
         <module>spring-kafka-2.x-plugin</module>
         <module>scheduled-annotation-plugin</module>
         <module>spring-webflux-5.x-webclient-plugin</module>
+        <module>spring-webflux-6.x-webclient-plugin</module>
         <module>resttemplate-commons</module>
     </modules>
     <packaging>pom</packaging>
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-5.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/webclient/define/WebFluxWebClientInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-5.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/webclient/define/WebFluxWebClientInstrumentation.java
index da87008fcf..70489730e3 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-5.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/webclient/define/WebFluxWebClientInstrumentation.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-5.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/webclient/define/WebFluxWebClientInstrumentation.java
@@ -18,8 +18,11 @@
 
 package org.apache.skywalking.apm.plugin.spring.webflux.v5.webclient.define;
 
+import java.util.Collections;
+import java.util.List;
 import net.bytebuddy.description.method.MethodDescription;
 import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
@@ -32,6 +35,8 @@ import static net.bytebuddy.matcher.ElementMatchers.named;
 public class WebFluxWebClientInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefineV2 {
     private static final String ENHANCE_CLASS = 
"org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction";
     private static final String INTERCEPT_CLASS = 
"org.apache.skywalking.apm.plugin.spring.webflux.v5.webclient.WebFluxWebClientInterceptor";
+    private static final String WEBFLUX_CONTEXT_WRITE_CLASS = 
"reactor.core.publisher.Mono";
+    private static final String WEBFLUX_CONTEXT_WRITE_METHOD = 
"subscriberContext";
 
     @Override
     protected ClassMatch enhanceClass() {
@@ -69,4 +74,10 @@ public class WebFluxWebClientInstrumentation extends 
ClassInstanceMethodsEnhance
     public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
         return new StaticMethodsInterceptPoint[0];
     }
+
+    @Override
+    protected List<WitnessMethod> witnessMethods() {
+        return Collections.singletonList(
+            new WitnessMethod(WEBFLUX_CONTEXT_WRITE_CLASS, 
named(WEBFLUX_CONTEXT_WRITE_METHOD)));
+    }
 }
\ No newline at end of file
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/pom.xml
similarity index 52%
copy from apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
copy to 
apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/pom.xml
index 95f7ff91fa..691973be6c 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/pom.xml
@@ -18,41 +18,23 @@
   -->
 
 <project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
-    <modelVersion>4.0.0</modelVersion>
-
     <parent>
+        <artifactId>spring-plugins</artifactId>
         <groupId>org.apache.skywalking</groupId>
-        <artifactId>apm-sdk-plugin</artifactId>
         <version>9.2.0-SNAPSHOT</version>
     </parent>
+    <modelVersion>4.0.0</modelVersion>
 
-    <artifactId>spring-plugins</artifactId>
-    <modules>
-        <module>async-annotation-plugin</module>
-        <module>concurrent-util-4.x-plugin</module>
-        <module>resttemplate-3.x-plugin</module>
-        <module>resttemplate-4.x-plugin</module>
-        <module>mvc-annotation-4.x-plugin</module>
-        <module>spring-cloud</module>
-        <module>mvc-annotation-3.x-plugin</module>
-        <module>core-patch</module>
-        <module>mvc-annotation-commons</module>
-        <module>spring-commons</module>
-        <module>mvc-annotation-5.x-plugin</module>
-        <module>spring-kafka-1.x-plugin</module>
-        <module>spring-kafka-2.x-plugin</module>
-        <module>scheduled-annotation-plugin</module>
-        <module>spring-webflux-5.x-webclient-plugin</module>
-        <module>resttemplate-commons</module>
-    </modules>
-    <packaging>pom</packaging>
+    <artifactId>spring-webflux-6.x-webclient-plugin</artifactId>
 
-    <name>apm-sdk-plugin</name>
     <url>http://maven.apache.org</url>
 
-    <properties>
-        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <sdk.plugin.related.dir>/..</sdk.plugin.related.dir>
-    </properties>
-
-</project>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webflux</artifactId>
+            <version>6.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/BodyInserterRequestInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/BodyInserterRequestInterceptor.java
new file mode 100644
index 0000000000..47bb3f610c
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/BodyInserterRequestInterceptor.java
@@ -0,0 +1,54 @@
+/*
+ * 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.webflux.v6.webclient;
+
+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.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.springframework.http.client.reactive.ClientHttpRequest;
+
+import java.lang.reflect.Method;
+
+public class BodyInserterRequestInterceptor implements 
InstanceMethodsAroundInterceptor {
+
+    @Override
+    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] 
allArguments, Class<?>[] argumentsTypes,
+                             MethodInterceptResult result) throws Throwable {
+        ClientHttpRequest clientHttpRequest = (ClientHttpRequest) 
allArguments[0];
+        ContextCarrier contextCarrier = (ContextCarrier) 
objInst.getSkyWalkingDynamicField();
+        CarrierItem next = contextCarrier.items();
+        while (next.hasNext()) {
+            next = next.next();
+            clientHttpRequest.getHeaders().set(next.getHeadKey(), 
next.getHeadValue());
+        }
+    }
+
+    @Override
+    public Object afterMethod(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes,
+                              Object ret) throws Throwable {
+        return ret;
+    }
+
+    @Override
+    public void handleMethodException(EnhancedInstance objInst, Method method, 
Object[] allArguments,
+                                      Class<?>[] argumentsTypes, Throwable t) {
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/WebFluxWebClientInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/WebFluxWebClientInterceptor.java
new file mode 100644
index 0000000000..32afedc6b0
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/WebFluxWebClientInterceptor.java
@@ -0,0 +1,126 @@
+/*
+ * 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.webflux.v6.webclient;
+
+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.ContextSnapshot;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.InstanceMethodsAroundInterceptorV2;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.MethodInvocationContext;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.web.reactive.function.client.ClientRequest;
+import org.springframework.web.reactive.function.client.ClientResponse;
+import reactor.core.publisher.Mono;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.util.Optional;
+
+public class WebFluxWebClientInterceptor implements 
InstanceMethodsAroundInterceptorV2 {
+
+    @Override
+    public void beforeMethod(EnhancedInstance objInst,
+                             Method method,
+                             Object[] allArguments,
+                             Class<?>[] argumentsTypes,
+                             MethodInvocationContext context) throws Throwable 
{
+
+    }
+
+    @Override
+    public Object afterMethod(EnhancedInstance objInst,
+                              Method method,
+                              Object[] allArguments,
+                              Class<?>[] argumentsTypes,
+                              Object ret,
+                              MethodInvocationContext context) throws 
Throwable {
+        // fix the problem that allArgument[0] may be null
+        if (allArguments[0] == null) {
+            return ret;
+        }
+        Mono<ClientResponse> ret1 = (Mono<ClientResponse>) ret;
+        return Mono.deferContextual(ctx -> {
+
+            ClientRequest request = (ClientRequest) allArguments[0];
+            URI uri = request.url();
+            final String operationName = getRequestURIString(uri);
+            final String remotePeer = getIPAndPort(uri);
+            AbstractSpan span = ContextManager.createExitSpan(operationName, 
remotePeer);
+
+            // get ContextSnapshot from reactor context,  the snapshot is set 
to reactor context by any other plugin
+            // such as DispatcherHandlerHandleMethodInterceptor in 
spring-webflux-5.x-plugin
+            final Optional<Object> optional = 
ctx.getOrEmpty("SKYWALKING_CONTEXT_SNAPSHOT");
+            optional.ifPresent(snapshot -> 
ContextManager.continued((ContextSnapshot) snapshot));
+
+            //set components name
+            span.setComponent(ComponentsDefine.SPRING_WEBCLIENT);
+            Tags.URL.set(span, uri.toString());
+            Tags.HTTP.METHOD.set(span, request.method().toString());
+            SpanLayer.asHttp(span);
+
+            final ContextCarrier contextCarrier = new ContextCarrier();
+            ContextManager.inject(contextCarrier);
+            if (request instanceof EnhancedInstance) {
+                ((EnhancedInstance) 
request).setSkyWalkingDynamicField(contextCarrier);
+            }
+
+            //user async interface
+            span.prepareForAsync();
+            ContextManager.stopSpan();
+            return ret1.doOnSuccess(clientResponse -> {
+                HttpStatusCode httpStatus = clientResponse.statusCode();
+                if (httpStatus != null) {
+                    Tags.HTTP_RESPONSE_STATUS_CODE.set(span, 
httpStatus.value());
+                    if (httpStatus.isError()) {
+                        span.errorOccurred();
+                    }
+                }
+            }).doOnError(span::log).doFinally(s -> {
+                span.asyncFinish();
+            });
+        });
+    }
+
+    @Override
+    public void handleMethodException(EnhancedInstance objInst,
+                                      Method method,
+                                      Object[] allArguments,
+                                      Class<?>[] argumentsTypes,
+                                      Throwable t,
+                                      MethodInvocationContext context) {
+        AbstractSpan activeSpan = ContextManager.activeSpan();
+        activeSpan.errorOccurred();
+        activeSpan.log(t);
+    }
+
+    private String getRequestURIString(URI uri) {
+        String requestPath = uri.getPath();
+        return requestPath != null && requestPath.length() > 0 ? requestPath : 
"/";
+    }
+
+    // return ip:port
+    private String getIPAndPort(URI uri) {
+        return uri.getHost() + ":" + uri.getPort();
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/define/BodyInserterRequestInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/define/BodyInserterRequestInstrumentation.java
new file mode 100644
index 0000000000..271263c40a
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/define/BodyInserterRequestInstrumentation.java
@@ -0,0 +1,67 @@
+/*
+ * 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.webflux.v6.webclient.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static 
org.apache.skywalking.apm.agent.core.plugin.bytebuddy.ArgumentTypeNameMatch.takesArgumentWithType;
+import static 
org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+public class BodyInserterRequestInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefine {
+
+    @Override
+    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+        return new ConstructorInterceptPoint[0];
+    }
+
+    @Override
+    public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() 
{
+        return new InstanceMethodsInterceptPoint[] {
+            new InstanceMethodsInterceptPoint() {
+                @Override
+                public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                    return named("writeTo").and(
+                        takesArgumentWithType(0, 
"org.springframework.http.client.reactive.ClientHttpRequest"));
+                }
+
+                @Override
+                public String getMethodsInterceptor() {
+                    return 
"org.apache.skywalking.apm.plugin.spring.webflux.v6.webclient.BodyInserterRequestInterceptor";
+                }
+
+                @Override
+                public boolean isOverrideArgs() {
+                    return false;
+                }
+            }
+        };
+    }
+
+    @Override
+    protected ClassMatch enhanceClass() {
+        return byName(
+            
"org.springframework.web.reactive.function.client.DefaultClientRequestBuilder$BodyInserterRequest");
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-5.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/webclient/define/WebFluxWebClientInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/define/WebFluxWebClientInstrumentation.java
similarity index 66%
copy from 
apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-5.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/webclient/define/WebFluxWebClientInstrumentation.java
copy to 
apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/define/WebFluxWebClientInstrumentation.java
index da87008fcf..0fd2e9fd68 100644
--- 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-5.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v5/webclient/define/WebFluxWebClientInstrumentation.java
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/webflux/v6/webclient/define/WebFluxWebClientInstrumentation.java
@@ -16,10 +16,11 @@
  *
  */
 
-package org.apache.skywalking.apm.plugin.spring.webflux.v5.webclient.define;
+package org.apache.skywalking.apm.plugin.spring.webflux.v6.webclient.define;
 
 import net.bytebuddy.description.method.MethodDescription;
 import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.WitnessMethod;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point;
 import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
@@ -27,11 +28,16 @@ import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.ClassI
 import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
 import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
 
+import java.util.Collections;
+import java.util.List;
+
 import static net.bytebuddy.matcher.ElementMatchers.named;
 
 public class WebFluxWebClientInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefineV2 {
     private static final String ENHANCE_CLASS = 
"org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction";
-    private static final String INTERCEPT_CLASS = 
"org.apache.skywalking.apm.plugin.spring.webflux.v5.webclient.WebFluxWebClientInterceptor";
+    private static final String INTERCEPT_CLASS = 
"org.apache.skywalking.apm.plugin.spring.webflux.v6.webclient.WebFluxWebClientInterceptor";
+    private static final String WEBFLUX_CONTEXT_WRITE_CLASS = 
"reactor.core.publisher.Mono";
+    private static final String WEBFLUX_CONTEXT_WRITE_METHOD = 
"deferContextual";
 
     @Override
     protected ClassMatch enhanceClass() {
@@ -45,23 +51,23 @@ public class WebFluxWebClientInstrumentation extends 
ClassInstanceMethodsEnhance
 
     @Override
     public InstanceMethodsInterceptV2Point[] 
getInstanceMethodsInterceptV2Points() {
-        return new InstanceMethodsInterceptV2Point[]{
-                new InstanceMethodsInterceptV2Point() {
-                    @Override
-                    public ElementMatcher<MethodDescription> 
getMethodsMatcher() {
-                        return named("exchange");
-                    }
+        return new InstanceMethodsInterceptV2Point[] {
+            new InstanceMethodsInterceptV2Point() {
+                @Override
+                public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                    return named("exchange");
+                }
 
-                    @Override
-                    public String getMethodsInterceptorV2() {
-                        return INTERCEPT_CLASS;
-                    }
+                @Override
+                public String getMethodsInterceptorV2() {
+                    return INTERCEPT_CLASS;
+                }
 
-                    @Override
-                    public boolean isOverrideArgs() {
-                        return false;
-                    }
+                @Override
+                public boolean isOverrideArgs() {
+                    return false;
                 }
+            }
         };
     }
 
@@ -69,4 +75,10 @@ public class WebFluxWebClientInstrumentation extends 
ClassInstanceMethodsEnhance
     public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
         return new StaticMethodsInterceptPoint[0];
     }
+
+    @Override
+    protected List<WitnessMethod> witnessMethods() {
+        return Collections.singletonList(
+            new WitnessMethod(WEBFLUX_CONTEXT_WRITE_CLASS, 
named(WEBFLUX_CONTEXT_WRITE_METHOD)));
+    }
 }
\ No newline at end of file
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/resources/skywalking-plugin.def
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..78e5e68070
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-webflux-6.x-webclient-plugin/src/main/resources/skywalking-plugin.def
@@ -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.
+
+spring-webflux-6.x-webclient=org.apache.skywalking.apm.plugin.spring.webflux.v6.webclient.define.BodyInserterRequestInstrumentation
+spring-webflux-6.x-webclient=org.apache.skywalking.apm.plugin.spring.webflux.v6.webclient.define.WebFluxWebClientInstrumentation
diff --git a/docs/en/setup/service-agent/java-agent/Plugin-list.md 
b/docs/en/setup/service-agent/java-agent/Plugin-list.md
index 9d6bbe77c0..3c0f2fed45 100644
--- a/docs/en/setup/service-agent/java-agent/Plugin-list.md
+++ b/docs/en/setup/service-agent/java-agent/Plugin-list.md
@@ -174,3 +174,4 @@
 - websphere-liberty-23.x
 - spring-cloud-gateway-4.x
 - spring-webflux-6.x
+- spring-webflux-6.x-webclient
diff --git a/docs/en/setup/service-agent/java-agent/Supported-list.md 
b/docs/en/setup/service-agent/java-agent/Supported-list.md
index 232d264d85..35ee22b092 100644
--- a/docs/en/setup/service-agent/java-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/java-agent/Supported-list.md
@@ -36,6 +36,7 @@ metrics based on the tracing data.
   * [Jetty Client](http://www.eclipse.org/jetty/) 9.x -> 11.x
   * [Apache httpcomponent 
AsyncClient](https://hc.apache.org/httpcomponents-asyncclient-4.1.x/) 4.x
   * [AsyncHttpClient](https://github.com/AsyncHttpClient/async-http-client) 
2.1+
+  * [Spring Webflux 
WebClient](https://github.com/spring-projects/spring-framework/tree/main/spring-webflux)
 5.x -> 6.x
   * JRE HttpURLConnection (Optional²)
   * [Hutool-http](https://www.hutool.cn/) client 5.x
   * [Micronaut HTTP 
Client](https://github.com/micronaut-projects/micronaut-core) 3.2.x -> 3.6.x
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/config/expectedData.yaml 
b/test/plugin/scenarios/httpexchange-scenario/config/expectedData.yaml
new file mode 100644
index 0000000000..8ed1b67531
--- /dev/null
+++ b/test/plugin/scenarios/httpexchange-scenario/config/expectedData.yaml
@@ -0,0 +1,150 @@
+# 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: httpexchange-projectA-scenario
+    segmentSize: nq 0
+    segments:
+      - segmentId: not null
+        spans:
+          - operationName: /testcase/success
+            parentSpanId: 0
+            spanId: 1
+            spanLayer: Http
+            startTime: not null
+            endTime: not null
+            componentId: 99
+            isError: false
+            spanType: Exit
+            peer: localhost:18080
+            skipAnalysis: false
+            tags:
+              - {key: url, value: 'http://localhost:18080/testcase/success'}
+              - {key: http.method, value: GET}
+              - {key: http.status_code, value: '200'}
+          - operationName: /testcase/url/urltest
+            parentSpanId: 0
+            spanId: 2
+            spanLayer: Http
+            startTime: not null
+            endTime: not null
+            componentId: 99
+            isError: false
+            spanType: Exit
+            peer: localhost:18080
+            skipAnalysis: false
+            tags:
+              - {key: url, value: 
'http://localhost:18080/testcase/url/urltest'}
+              - {key: http.method, value: GET}
+              - {key: http.status_code, value: '200'}
+          - operationName: /testcase/body
+            parentSpanId: 0
+            spanId: 3
+            spanLayer: Http
+            startTime: not null
+            endTime: not null
+            componentId: 99
+            isError: false
+            spanType: Exit
+            peer: localhost:18080
+            skipAnalysis: false
+            tags:
+              - {key: url, value: 'http://localhost:18080/testcase/body'}
+              - {key: http.method, value: POST}
+              - {key: http.status_code, value: '200'}
+          - operationName: GET:/projectA/testcase
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
+            startTime: not null
+            endTime: not null
+            componentId: 1
+            isError: false
+            spanType: Entry
+            peer: ''
+            skipAnalysis: false
+            tags:
+              - {key: url, value: 'http://localhost:8080/projectA/testcase'}
+              - {key: http.method, value: GET}
+              - {key: http.status_code, value: '200'}
+  - serviceName: httpexchange-projectB-scenario
+    segmentSize: nq 0
+    segments:
+      - segmentId: not null
+        spans:
+          - operationName: GET:/testcase/success
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
+            startTime: not null
+            endTime: not null
+            componentId: 1
+            isError: false
+            spanType: Entry
+            peer: ''
+            skipAnalysis: false
+            tags:
+              - {key: url, value: 'http://localhost:18080/testcase/success'}
+              - {key: http.method, value: GET}
+              - {key: http.status_code, value: '200'}
+            refs:
+              - {parentEndpoint: 'GET:/projectA/testcase', networkAddress: 
'localhost:18080',
+                 refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: 
not null,
+                 parentServiceInstance: not null, parentService: 
httpexchange-projectA-scenario,
+                 traceId: not null}
+      - segmentId: not null
+        spans:
+          - operationName: GET:/testcase/url/urltest
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
+            startTime: not null
+            endTime: not null
+            componentId: 1
+            isError: false
+            spanType: Entry
+            peer: ''
+            skipAnalysis: false
+            tags:
+              - {key: url, value: 
'http://localhost:18080/testcase/url/urltest'}
+              - {key: http.method, value: GET}
+              - {key: http.status_code, value: '200'}
+            refs:
+              - {parentEndpoint: 'GET:/projectA/testcase', networkAddress: 
'localhost:18080',
+                 refType: CrossProcess, parentSpanId: 2, parentTraceSegmentId: 
not null,
+                 parentServiceInstance: not null, parentService: 
httpexchange-projectA-scenario,
+                 traceId: not null}
+      - segmentId: not null
+        spans:
+          - operationName: POST:/testcase/body
+            parentSpanId: -1
+            spanId: 0
+            spanLayer: Http
+            startTime: not null
+            endTime: not null
+            componentId: 1
+            isError: false
+            spanType: Entry
+            peer: ''
+            skipAnalysis: false
+            tags:
+              - {key: url, value: 'http://localhost:18080/testcase/body'}
+              - {key: http.method, value: POST}
+              - {key: http.status_code, value: '200'}
+            refs:
+              - {parentEndpoint: 'GET:/projectA/testcase', networkAddress: 
'localhost:18080',
+                 refType: CrossProcess, parentSpanId: 3, parentTraceSegmentId: 
not null,
+                 parentServiceInstance: not null, parentService: 
httpexchange-projectA-scenario,
+                 traceId: not null}
\ No newline at end of file
diff --git a/test/plugin/scenarios/httpexchange-scenario/configuration.yml 
b/test/plugin/scenarios/httpexchange-scenario/configuration.yml
new file mode 100644
index 0000000000..bbf0b958e3
--- /dev/null
+++ b/test/plugin/scenarios/httpexchange-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/projectA/testcase
+healthCheck: http://localhost:8080/projectA/healthCheck
+startScript: ./bin/startup.sh
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-dist/bin/startup.sh 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-dist/bin/startup.sh
new file mode 100644
index 0000000000..a29066f697
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-dist/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.
+
+home="$(cd "$(dirname $0)"; pwd)"
+
+java -jar ${agent_opts} 
"-Dskywalking.agent.service_name=httpexchange-projectA-scenario" 
${home}/../libs/httpexchange-projectA-scenario.jar &
+sleep 1
+
+java -jar ${agent_opts} 
"-Dskywalking.agent.service_name=httpexchange-projectB-scenario" 
${home}/../libs/httpexchange-projectB-scenario.jar &
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-dist/pom.xml 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-dist/pom.xml
new file mode 100644
index 0000000000..b40480cff4
--- /dev/null
+++ b/test/plugin/scenarios/httpexchange-scenario/httpexchange-dist/pom.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <groupId>org.apache.skywalking</groupId>
+        <artifactId>httpexchange-scenario</artifactId>
+        <version>5.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>httpexchange-dist</artifactId>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>assemble</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                
<descriptor>src/main/assembly/assembly.xml</descriptor>
+                            </descriptors>
+                            <outputDirectory>../target/</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-dist/src/main/assembly/assembly.xml
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-dist/src/main/assembly/assembly.xml
new file mode 100644
index 0000000000..5e4a44d1d2
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-dist/src/main/assembly/assembly.xml
@@ -0,0 +1,46 @@
+<?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>
+    </fileSets>
+
+    <files>
+        <file>
+            
<source>../httpexchange-projectA-scenario/target/httpexchange-projectA-scenario.jar</source>
+            <outputDirectory>./libs</outputDirectory>
+            <fileMode>0775</fileMode>
+        </file>
+        <file>
+            
<source>../httpexchange-projectB-scenario/target/httpexchange-projectB-scenario.jar</source>
+            <outputDirectory>./libs</outputDirectory>
+            <fileMode>0775</fileMode>
+        </file>
+    </files>
+</assembly>
\ No newline at end of file
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/pom.xml
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/pom.xml
new file mode 100644
index 0000000000..f535eed310
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/pom.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <groupId>org.apache.skywalking</groupId>
+        <artifactId>httpexchange-scenario</artifactId>
+        <version>5.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>httpexchange-projectA-scenario</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${test.framework.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-webflux</artifactId>
+            <version>${test.framework.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>httpexchange-projectA-scenario</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>3.0.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/PorjectaApplication.java
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/PorjectaApplication.java
new file mode 100644
index 0000000000..dc89fd7bb8
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/PorjectaApplication.java
@@ -0,0 +1,29 @@
+/*
+ * 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.testcase.sc.httpexchange.projectA;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class PorjectaApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(PorjectaApplication.class, args);
+    }
+}
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/api/TestcaseClient.java
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/api/TestcaseClient.java
new file mode 100644
index 0000000000..873d117040
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/api/TestcaseClient.java
@@ -0,0 +1,43 @@
+/*
+ * 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.testcase.sc.httpexchange.projectA.api;
+
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.service.annotation.GetExchange;
+import org.springframework.web.service.annotation.HttpExchange;
+import org.springframework.web.service.annotation.PostExchange;
+
+@HttpExchange("/testcase")
+public interface TestcaseClient {
+
+    @GetExchange("/healthCheck")
+    String healthCheck();
+
+    @GetExchange("/success")
+    String success();
+
+    @GetExchange("/error")
+    String error();
+
+    @GetExchange("/url/{test}")
+    String urlParams(@PathVariable("test") String test);
+
+    @PostExchange(value = "/body")
+    String bodyParams(@RequestBody String body);
+}
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/config/RestClientConfig.java
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/config/RestClientConfig.java
new file mode 100644
index 0000000000..81a6b5ac73
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/config/RestClientConfig.java
@@ -0,0 +1,43 @@
+/*
+ * 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.testcase.sc.httpexchange.projectA.config;
+
+import 
org.apache.skywalking.apm.testcase.sc.httpexchange.projectA.api.TestcaseClient;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.reactive.function.client.WebClient;
+import 
org.springframework.web.reactive.function.client.support.WebClientAdapter;
+import org.springframework.web.service.invoker.HttpServiceProxyFactory;
+
+@Configuration
+public class RestClientConfig {
+    @Value("${projectB.host:localhost:18080}")
+    private String hostbAddress;
+
+    @Bean
+    public TestcaseClient testcaseClient() {
+        WebClient client = WebClient.builder()
+                                    .baseUrl("http://"; + hostbAddress + "/")
+                                    .build();
+        HttpServiceProxyFactory factory = HttpServiceProxyFactory
+            .builderFor(WebClientAdapter.create(client))
+            .build();
+        return factory.createClient(TestcaseClient.class);
+    }
+}
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/controller/TestController.java
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/controller/TestController.java
new file mode 100644
index 0000000000..15b013e917
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/java/org/apache/skywalking/apm/testcase/sc/httpexchange/projectA/controller/TestController.java
@@ -0,0 +1,51 @@
+/*
+ * 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.testcase.sc.httpexchange.projectA.controller;
+
+import java.io.IOException;
+import 
org.apache.skywalking.apm.testcase.sc.httpexchange.projectA.api.TestcaseClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class TestController {
+
+    @Autowired
+    private TestcaseClient testcaseClient;
+
+    @RequestMapping("/testcase")
+    public String testcase() {
+        testcaseClient.success();
+//        try {
+//            testcaseClient.error();
+//        } catch (Exception e) {
+//            //mock up error request
+//        }
+        testcaseClient.urlParams("urltest");
+        testcaseClient.bodyParams("bodytest");
+        return "test";
+    }
+
+    @RequestMapping("/healthCheck")
+    public String healthCheck() throws IOException {
+        testcaseClient.healthCheck();
+        return "test";
+    }
+
+}
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/resources/application.yml
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/resources/application.yml
new file mode 100644
index 0000000000..ed94822fb4
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectA-scenario/src/main/resources/application.yml
@@ -0,0 +1,23 @@
+#
+# 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:
+  servlet:
+    context-path: /projectA
+  port: 8080
+projectB:
+  host: "localhost:18080"
\ No newline at end of file
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/pom.xml
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/pom.xml
new file mode 100644
index 0000000000..b35ab6167e
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/pom.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <artifactId>httpexchange-scenario</artifactId>
+        <groupId>org.apache.skywalking</groupId>
+        <version>5.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>httpexchange-projectB-scenario</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${test.framework.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>httpexchange-projectB-scenario</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>3.0.0</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/httpexchange/projectB/ProjectbApplication.java
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/httpexchange/projectB/ProjectbApplication.java
new file mode 100644
index 0000000000..9efea702f0
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/httpexchange/projectB/ProjectbApplication.java
@@ -0,0 +1,29 @@
+/*
+ *  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.httpexchange.projectB;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class ProjectbApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(ProjectbApplication.class, args);
+    }
+}
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/httpexchange/projectB/controller/TestAnnotationController.java
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/httpexchange/projectB/controller/TestAnnotationController.java
new file mode 100644
index 0000000000..8cef8bb42d
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/src/main/java/test/apache/skywalking/apm/testcase/sc/httpexchange/projectB/controller/TestAnnotationController.java
@@ -0,0 +1,50 @@
+/*
+ *  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.httpexchange.projectB.controller;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class TestAnnotationController {
+
+    @RequestMapping("/testcase/success")
+    public String success() {
+        return "1";
+    }
+
+    @GetMapping("/testcase/url/{test}")
+    public String urlParams(@PathVariable("test") String var) {
+        return var;
+    }
+
+    @PostMapping("/testcase/body")
+    public String bodyParams(@RequestBody(required = false) String body) {
+        return body;
+    }
+
+    @RequestMapping("/testcase/healthCheck")
+    public String healthCheck() {
+        return "healthCheck";
+    }
+
+}
diff --git 
a/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/src/main/resources/application.yml
 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/src/main/resources/application.yml
new file mode 100644
index 0000000000..5801ab6a1a
--- /dev/null
+++ 
b/test/plugin/scenarios/httpexchange-scenario/httpexchange-projectB-scenario/src/main/resources/application.yml
@@ -0,0 +1,19 @@
+#
+# 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: 18080
\ No newline at end of file
diff --git a/test/plugin/scenarios/httpexchange-scenario/pom.xml 
b/test/plugin/scenarios/httpexchange-scenario/pom.xml
new file mode 100644
index 0000000000..27edd11cb4
--- /dev/null
+++ b/test/plugin/scenarios/httpexchange-scenario/pom.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.skywalking</groupId>
+    <artifactId>httpexchange-scenario</artifactId>
+    <packaging>pom</packaging>
+    <version>5.0.0</version>
+    <modules>
+        <module>httpexchange-projectA-scenario</module>
+        <module>httpexchange-projectB-scenario</module>
+        <module>httpexchange-dist</module>
+    </modules>
+
+    <name>skywalking-httpexchange-scenario</name>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <compiler.version>17</compiler.version>
+        <maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
+        <test.framework.version>3.2.0</test.framework.version>
+        <docker.image.version>${test.framework.version}</docker.image.version>
+    </properties>
+
+    <build>
+        <finalName>httpexchange-scenario</finalName>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven-compiler-plugin.version}</version>
+                <configuration>
+                    <source>${compiler.version}</source>
+                    <target>${compiler.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/test/plugin/scenarios/httpexchange-scenario/support-version.list 
b/test/plugin/scenarios/httpexchange-scenario/support-version.list
new file mode 100644
index 0000000000..7da7dc2815
--- /dev/null
+++ b/test/plugin/scenarios/httpexchange-scenario/support-version.list
@@ -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.
+
+# 3.0.x,3.1.x are supported, but the creation method of client is deprecated, 
so we don’t test them.
+3.2.0

Reply via email to