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 233effa70f Add Spring RabbitMQ plugin (#796)
233effa70f is described below

commit 233effa70f86f3d6d53dfc4b8a4aa4817143e58c
Author: liuhaolong10 <[email protected]>
AuthorDate: Fri Mar 13 10:37:13 2026 +0800

    Add Spring RabbitMQ plugin (#796)
---
 .github/workflows/plugins-jdk17-test.0.yaml        |   1 +
 CHANGES.md                                         |   1 +
 .../rabbitmq/RabbitMQConsumerInterceptor.java      |   9 +
 apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml  |   3 +-
 .../spring-plugins/spring-rabbitmq-plugin/pom.xml  |  46 +++++
 .../SpringRabbitMQConsumerInterceptor.java         | 146 ++++++++++++++++
 .../SpringRabbitMQConsumerInstrumentation.java     |  69 ++++++++
 .../src/main/resources/skywalking-plugin.def       |  17 ++
 .../RabbitMQSpringConsumerInterceptorTest.java     | 192 +++++++++++++++++++++
 .../setup/service-agent/java-agent/Plugin-list.md  |   1 +
 .../service-agent/java-agent/Supported-list.md     |   1 +
 .../spring-rabbitmq-scenario/bin/startup.sh        |  20 +++
 .../config/expectedData.yaml                       | 165 ++++++++++++++++++
 .../spring-rabbitmq-scenario/configuration.yml     |  33 ++++
 .../scenarios/spring-rabbitmq-scenario/pom.xml     | 117 +++++++++++++
 .../src/main/assembly/assembly.xml                 |  41 +++++
 .../apm/testcase/spring/rabbitmq/Application.java  |  30 ++++
 .../spring/rabbitmq/config/RabbitMqConfig.java     |  54 ++++++
 .../spring/rabbitmq/controller/CaseController.java |  85 +++++++++
 .../src/main/resources/application.yml             |  29 ++++
 .../src/main/resources/log4j2.xml                  |  31 ++++
 .../spring-rabbitmq-scenario/support-version.list  |  18 ++
 22 files changed, 1108 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/plugins-jdk17-test.0.yaml 
b/.github/workflows/plugins-jdk17-test.0.yaml
index 092fa2daae..74ae79f0fe 100644
--- a/.github/workflows/plugins-jdk17-test.0.yaml
+++ b/.github/workflows/plugins-jdk17-test.0.yaml
@@ -80,6 +80,7 @@ jobs:
           - jetty-11.x-scenario
           - jetty-10.x-scenario
           - spring-ai-1.x-scenario
+          - spring-rabbitmq-scenario
     steps:
       - uses: actions/checkout@v2
         with:
diff --git a/CHANGES.md b/CHANGES.md
index 47b9ac0d94..e49c314aab 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -8,6 +8,7 @@ Release Notes.
 * Added support for Lettuce reactive Redis commands.
 * Add Spring AI 1.x plugin and GenAI layer.
 * Fix httpclient-5.x plugin injecting sw8 propagation headers into ClickHouse 
HTTP requests (port 8123), causing HTTP 400. Add `PROPAGATION_EXCLUDE_PORTS` 
config to skip tracing (including header injection) for specified ports in the 
classic client interceptor.
+* Add Spring RabbitMQ 2.x - 4.x plugin.
 
 All issues and pull requests are 
[here](https://github.com/apache/skywalking/milestone/249?closed=1)
 
diff --git 
a/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/RabbitMQConsumerInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/RabbitMQConsumerInterceptor.java
index 50240c9729..3ac0caf121 100644
--- 
a/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/RabbitMQConsumerInterceptor.java
+++ 
b/apm-sniffer/apm-sdk-plugin/rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/rabbitmq/RabbitMQConsumerInterceptor.java
@@ -26,10 +26,19 @@ import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInt
 
 public class RabbitMQConsumerInterceptor implements 
InstanceMethodsAroundInterceptor {
 
+    public static final String SMLC_INTERNAL_CONSUMER = 
"org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$InternalConsumer";
+    public static final String DMLC_INTERNAL_CONSUMER = 
"org.springframework.amqp.rabbit.listener.DirectMessageListenerContainer$SimpleConsumer";
+
     @Override
     public void beforeMethod(EnhancedInstance objInst, Method method, Object[] 
allArguments, Class<?>[] argumentsTypes,
         MethodInterceptResult result) throws Throwable {
         Consumer consumer = (Consumer) allArguments[6];
+        if (consumer != null) {
+            String className = consumer.getClass().getName();
+            if (SMLC_INTERNAL_CONSUMER.equals(className) || 
DMLC_INTERNAL_CONSUMER.equals(className)) {
+                return;
+            }
+        }
         allArguments[6] = new TracerConsumer(consumer, (String) 
objInst.getSkyWalkingDynamicField());
     }
 
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
index 5a307810b3..4326ec7354 100644
--- a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
@@ -46,10 +46,11 @@
         <module>spring-webflux-6.x-webclient-plugin</module>
         <module>resttemplate-commons</module>
         <module>spring-ai-1.x-plugin</module>
+        <module>spring-rabbitmq-plugin</module>
     </modules>
     <packaging>pom</packaging>
 
-    <name>apm-sdk-plugin</name>
+    <name>spring-plugins</name>
     <url>http://maven.apache.org</url>
 
     <properties>
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/pom.xml 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/pom.xml
new file mode 100644
index 0000000000..cb0c687268
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/pom.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.
+  ~
+  -->
+<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>
+        <groupId>org.apache.skywalking</groupId>
+        <artifactId>spring-plugins</artifactId>
+        <version>9.7.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>apm-spring-rabbitmq-plugin</artifactId>
+    <name>apm-spring-rabbitmq-plugin</name>
+    <packaging>jar</packaging>
+
+    <properties>
+        <spring-rabbit.version>3.0.0</spring-rabbit.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.amqp</groupId>
+            <artifactId>spring-rabbit</artifactId>
+            <version>${spring-rabbit.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/rabbitmq/SpringRabbitMQConsumerInterceptor.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/rabbitmq/SpringRabbitMQConsumerInterceptor.java
new file mode 100644
index 0000000000..29bf40599f
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/rabbitmq/SpringRabbitMQConsumerInterceptor.java
@@ -0,0 +1,146 @@
+/*
+ * 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.rabbitmq;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.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.amqp.core.Message;
+import org.springframework.amqp.core.MessageProperties;
+
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.Connection;
+
+public class SpringRabbitMQConsumerInterceptor implements 
InstanceMethodsAroundInterceptorV2 {
+    public static final String OPERATE_NAME_PREFIX = "RabbitMQ/";
+    public static final String CONSUMER_OPERATE_NAME_SUFFIX = "/Consumer";
+
+    @Override
+    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] 
allArguments, Class<?>[] argumentsTypes,
+        MethodInvocationContext context) throws Throwable {
+        Channel channel = (Channel) allArguments[0];
+
+        if (allArguments[1] instanceof Message) {
+            // Single message consume
+            Message message = (Message) allArguments[1];
+            MessageProperties messageProperties = 
message.getMessageProperties();
+            Map<String, Object> headers = messageProperties.getHeaders();
+
+            ContextCarrier contextCarrier = buildContextCarrier(headers);
+            String operationName = buildOperationName(messageProperties);
+            AbstractSpan activeSpan = 
ContextManager.createEntrySpan(operationName, contextCarrier);
+
+            setSpanAttributes(activeSpan, channel, messageProperties);
+        } else if (allArguments[1] instanceof List) {
+            // Batch message consume
+            List<?> messages = (List<?>) allArguments[1];
+            if (messages.isEmpty()) {
+                return;
+            }
+
+            // Use the first message to create EntrySpan
+            Message firstMessage = (Message) messages.get(0);
+            MessageProperties firstMessageProperties = 
firstMessage.getMessageProperties();
+            Map<String, Object> firstMessageHeaders = 
firstMessageProperties.getHeaders();
+
+            ContextCarrier contextCarrier = 
buildContextCarrier(firstMessageHeaders);
+            String operationName = buildOperationName(firstMessageProperties);
+            AbstractSpan activeSpan = 
ContextManager.createEntrySpan(operationName, contextCarrier);
+
+            setSpanAttributes(activeSpan, channel, firstMessageProperties);
+
+            // Extract trace context from remaining messages (skip first, 
already used for EntrySpan)
+            // to correlate all producer traces with this consumer span
+            for (int i = 1; i < messages.size(); i++) {
+                Object msg = messages.get(i);
+                if (msg instanceof Message) {
+                    Message message = (Message) msg;
+                    MessageProperties messageProperties = 
message.getMessageProperties();
+                    Map<String, Object> headers = 
messageProperties.getHeaders();
+
+                    ContextCarrier carrier = buildContextCarrier(headers);
+                    if (carrier.isValid()) {
+                        ContextManager.extract(carrier);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Build ContextCarrier from message headers
+     */
+    private ContextCarrier buildContextCarrier(Map<String, Object> headers) {
+        ContextCarrier contextCarrier = new ContextCarrier();
+        CarrierItem next = contextCarrier.items();
+        while (next.hasNext()) {
+            next = next.next();
+            Object value = headers.get(next.getHeadKey());
+            if (value != null) {
+                next.setHeadValue(value.toString());
+            }
+        }
+        return contextCarrier;
+    }
+
+    private String buildOperationName(MessageProperties messageProperties) {
+        return OPERATE_NAME_PREFIX + "Topic/" + 
messageProperties.getReceivedExchange()
+               + "Queue/" + messageProperties.getReceivedRoutingKey()
+               + CONSUMER_OPERATE_NAME_SUFFIX;
+    }
+
+    private void setSpanAttributes(AbstractSpan span, Channel channel, 
MessageProperties messageProperties) {
+        Connection connection = channel.getConnection();
+        String serverUrl = connection.getAddress().getHostAddress() + ":" + 
connection.getPort();
+        Tags.MQ_BROKER.set(span, serverUrl);
+        Tags.MQ_TOPIC.set(span, messageProperties.getReceivedExchange());
+        Tags.MQ_QUEUE.set(span, messageProperties.getReceivedRoutingKey());
+        span.setComponent(ComponentsDefine.RABBITMQ_CONSUMER);
+        span.setPeer(serverUrl);
+        SpanLayer.asMQ(span);
+    }
+
+    @Override
+    public Object afterMethod(EnhancedInstance objInst, Method method, 
Object[] allArguments, Class<?>[] argumentsTypes,
+        Object ret, MethodInvocationContext context) throws Throwable {
+        if (ContextManager.isActive()) {
+            ContextManager.stopSpan();
+        }
+        return ret;
+    }
+
+    @Override
+    public void handleMethodException(EnhancedInstance objInst, Method method, 
Object[] allArguments,
+        Class<?>[] argumentsTypes, Throwable t, MethodInvocationContext 
context) {
+        if (ContextManager.isActive()) {
+            ContextManager.activeSpan().log(t);
+        }
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/rabbitmq/define/SpringRabbitMQConsumerInstrumentation.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/rabbitmq/define/SpringRabbitMQConsumerInstrumentation.java
new file mode 100644
index 0000000000..b4a541adc8
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/rabbitmq/define/SpringRabbitMQConsumerInstrumentation.java
@@ -0,0 +1,69 @@
+/*
+ * 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.rabbitmq.define;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.v2.ClassInstanceMethodsEnhancePluginDefineV2;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.DeclaredInstanceMethodsInterceptV2Point;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.v2.InstanceMethodsInterceptV2Point;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+
+public class SpringRabbitMQConsumerInstrumentation extends 
ClassInstanceMethodsEnhancePluginDefineV2 {
+    public static final String ENHANCE_CLASS = 
"org.springframework.amqp.rabbit.listener.AbstractMessageListenerContainer";
+    public static final String ENHANCE_METHOD = "executeListener";
+    public static final String INTERCEPTOR_CLASS = 
"org.apache.skywalking.apm.plugin.spring.rabbitmq.SpringRabbitMQConsumerInterceptor";
+
+    @Override
+    public ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+        return null;
+    }
+
+    @Override
+    public InstanceMethodsInterceptV2Point[] 
getInstanceMethodsInterceptV2Points() {
+        return new InstanceMethodsInterceptV2Point[] {
+            new DeclaredInstanceMethodsInterceptV2Point() {
+                @Override
+                public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                    return named(ENHANCE_METHOD);
+                }
+
+                @Override
+                public String getMethodsInterceptorV2() {
+                    return INTERCEPTOR_CLASS;
+                }
+
+                @Override
+                public boolean isOverrideArgs() {
+                    return false;
+                }
+            }
+        };
+    }
+
+    @Override
+    protected ClassMatch enhanceClass() {
+        return NameMatch.byName(ENHANCE_CLASS);
+    }
+}
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/main/resources/skywalking-plugin.def
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000..94d87de414
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,17 @@
+# 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-rabbitmq=org.apache.skywalking.apm.plugin.spring.rabbitmq.define.SpringRabbitMQConsumerInstrumentation
\ No newline at end of file
diff --git 
a/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/rabbitmq/RabbitMQSpringConsumerInterceptorTest.java
 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/rabbitmq/RabbitMQSpringConsumerInterceptorTest.java
new file mode 100644
index 0000000000..e29864204e
--- /dev/null
+++ 
b/apm-sniffer/apm-sdk-plugin/spring-plugins/spring-rabbitmq-plugin/src/test/java/org/apache/skywalking/apm/plugin/spring/rabbitmq/RabbitMQSpringConsumerInterceptorTest.java
@@ -0,0 +1,192 @@
+/*
+ * 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.rabbitmq;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.skywalking.apm.agent.core.context.SW8CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import 
org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.test.tools.AgentServiceRule;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStorage;
+import org.apache.skywalking.apm.agent.test.tools.SegmentStoragePoint;
+import org.apache.skywalking.apm.agent.test.tools.TracingSegmentRunner;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.core.MessageProperties;
+
+import com.rabbitmq.client.Channel;
+import com.rabbitmq.client.Connection;
+
+@RunWith(TracingSegmentRunner.class)
+public class RabbitMQSpringConsumerInterceptorTest {
+
+    @SegmentStoragePoint
+    private SegmentStorage segmentStorage;
+
+    private SpringRabbitMQConsumerInterceptor rabbitMQConsumerInterceptor;
+
+    @Mock
+    private EnhancedInstance enhancedInstance;
+
+    @Rule
+    public AgentServiceRule serviceRule = new AgentServiceRule();
+
+    @Before
+    public void setUp() throws Exception {
+        rabbitMQConsumerInterceptor = new SpringRabbitMQConsumerInterceptor();
+    }
+
+    @Test
+    public void testRabbitMQConsumerInterceptorWithNilHeaders() throws 
Throwable {
+        Object[] args = prepareMockData(false);
+        rabbitMQConsumerInterceptor.beforeMethod(enhancedInstance, null, args, 
new Class[0], null);
+        rabbitMQConsumerInterceptor.afterMethod(enhancedInstance, null, args, 
new Class[0], null, null);
+        List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
+        Assert.assertThat(traceSegments.size(), is(1));
+    }
+
+    @Test
+    public void testRabbitMQConsumerInterceptor() throws Throwable {
+        Object[] args = prepareMockData(true);
+        rabbitMQConsumerInterceptor.beforeMethod(enhancedInstance, null, args, 
new Class[0], null);
+        rabbitMQConsumerInterceptor.afterMethod(enhancedInstance, null, args, 
new Class[0], null, null);
+        List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
+        Assert.assertThat(traceSegments.size(), is(1));
+    }
+
+    @Test
+    public void testBatchMessageConsumption() throws Throwable {
+        Object[] args = prepareMockBatchData(true);
+        rabbitMQConsumerInterceptor.beforeMethod(enhancedInstance, null, args, 
new Class[0], null);
+        rabbitMQConsumerInterceptor.afterMethod(enhancedInstance, null, args, 
new Class[0], null, null);
+        List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
+        Assert.assertThat(traceSegments.size(), is(1));
+    }
+
+    @Test
+    public void testEmptyBatchMessageConsumption() throws Throwable {
+        Channel channel = mock(Channel.class);
+        Connection connection = mock(Connection.class);
+        InetAddress address = mock(InetAddress.class);
+
+        when(channel.getConnection()).thenReturn(connection);
+        when(connection.getAddress()).thenReturn(address);
+        when(address.getHostAddress()).thenReturn("127.0.0.1");
+        when(connection.getPort()).thenReturn(5672);
+
+        Object[] args = new Object[] {channel, new 
java.util.ArrayList<Message>()};
+        rabbitMQConsumerInterceptor.beforeMethod(enhancedInstance, null, args, 
new Class[0], null);
+        rabbitMQConsumerInterceptor.afterMethod(enhancedInstance, null, args, 
new Class[0], null, null);
+        List<TraceSegment> traceSegments = segmentStorage.getTraceSegments();
+        Assert.assertThat(traceSegments.size(), is(0));
+    }
+
+    private Object[] prepareMockData(boolean withHeaders) throws Exception {
+        Channel channel = mock(Channel.class);
+        Connection connection = mock(Connection.class);
+        InetAddress address = mock(InetAddress.class);
+        Message message = mock(Message.class);
+        MessageProperties messageProperties = mock(MessageProperties.class);
+
+        when(channel.getConnection()).thenReturn(connection);
+        when(connection.getAddress()).thenReturn(address);
+        when(address.getHostAddress()).thenReturn("127.0.0.1");
+        when(connection.getPort()).thenReturn(5672);
+        when(message.getMessageProperties()).thenReturn(messageProperties);
+        
when(messageProperties.getReceivedExchange()).thenReturn("test-exchange");
+        
when(messageProperties.getReceivedRoutingKey()).thenReturn("test-routing-key");
+
+        if (withHeaders) {
+            Map<String, Object> headers = new HashMap<>();
+            headers.put(SW8CarrierItem.HEADER_NAME,
+                
"1-My40LjU=-MS4yLjM=-3-c2VydmljZQ==-aW5zdGFuY2U=-L2FwcA==-MTI3LjAuMC4xOjgwODA=");
+            when(messageProperties.getHeader(SW8CarrierItem.HEADER_NAME))
+                .thenReturn(headers.get(SW8CarrierItem.HEADER_NAME));
+        }
+
+        return new Object[] {channel, message};
+    }
+
+    private Object[] prepareMockBatchData(boolean withHeaders) throws 
Exception {
+        Channel channel = mock(Channel.class);
+        Connection connection = mock(Connection.class);
+        InetAddress address = mock(InetAddress.class);
+
+        when(channel.getConnection()).thenReturn(connection);
+        when(connection.getAddress()).thenReturn(address);
+        when(address.getHostAddress()).thenReturn("127.0.0.1");
+        when(connection.getPort()).thenReturn(5672);
+
+        Message message1 = mock(Message.class);
+        Message message2 = mock(Message.class);
+        Message message3 = mock(Message.class);
+        MessageProperties props1 = mock(MessageProperties.class);
+        MessageProperties props2 = mock(MessageProperties.class);
+        MessageProperties props3 = mock(MessageProperties.class);
+
+        when(message1.getMessageProperties()).thenReturn(props1);
+        when(message2.getMessageProperties()).thenReturn(props2);
+        when(message3.getMessageProperties()).thenReturn(props3);
+
+        when(props1.getReceivedExchange()).thenReturn("test-exchange");
+        when(props1.getReceivedRoutingKey()).thenReturn("test-routing-key");
+        when(props2.getReceivedExchange()).thenReturn("test-exchange");
+        when(props2.getReceivedRoutingKey()).thenReturn("test-routing-key");
+        when(props3.getReceivedExchange()).thenReturn("test-exchange");
+        when(props3.getReceivedRoutingKey()).thenReturn("test-routing-key");
+
+        if (withHeaders) {
+            Map<String, Object> headers1 = new HashMap<>();
+            headers1.put(SW8CarrierItem.HEADER_NAME,
+                
"1-My40LjU=-MS4yLjM=-3-c2VydmljZQ==-aW5zdGFuY2U=-L2FwcA==-MTI3LjAuMC4xOjgwODA=");
+            when(props1.getHeader(SW8CarrierItem.HEADER_NAME))
+                .thenReturn(headers1.get(SW8CarrierItem.HEADER_NAME));
+
+            Map<String, Object> headers2 = new HashMap<>();
+            headers2.put(SW8CarrierItem.HEADER_NAME,
+                
"1-NTY3Ljg=-OS4xMC4xMQ==-12-ZXJ2aWNlMg==-aW5zdGFuY2UyLU9hcHA=-MTI3LjAuMC4yOjgwODA=");
+            when(props2.getHeader(SW8CarrierItem.HEADER_NAME))
+                .thenReturn(headers2.get(SW8CarrierItem.HEADER_NAME));
+
+            Map<String, Object> headers3 = new HashMap<>();
+            headers3.put(SW8CarrierItem.HEADER_NAME,
+                
"1-MTExLjIyMi4zMzM=-NDQ0LjU1NS42NjY=-MzQ1-ZXJ2aWNlMw==-aW5zdGFuY2UzLU9hcHA=-MTI3LjAuMC4zOjgwODA=");
+            when(props3.getHeader(SW8CarrierItem.HEADER_NAME))
+                .thenReturn(headers3.get(SW8CarrierItem.HEADER_NAME));
+        }
+
+        List<Message> messages = new ArrayList<>(Arrays.asList(message1, 
message2, message3));
+        return new Object[] {channel, messages};
+    }
+}
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 49d1cb9c8e..3764ae9716 100644
--- a/docs/en/setup/service-agent/java-agent/Plugin-list.md
+++ b/docs/en/setup/service-agent/java-agent/Plugin-list.md
@@ -114,6 +114,7 @@
 - spring-core-patch
 - spring-kafka-1.x
 - spring-kafka-2.x
+- spring-rabbitmq
 - spring-mvc-annotation
 - spring-mvc-annotation-3.x
 - spring-mvc-annotation-4.x
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 cdadd27422..1645c43b4e 100644
--- a/docs/en/setup/service-agent/java-agent/Supported-list.md
+++ b/docs/en/setup/service-agent/java-agent/Supported-list.md
@@ -80,6 +80,7 @@ metrics based on the tracing data.
   * [Spring-Kafka](https://github.com/spring-projects/spring-kafka) Spring 
Kafka Consumer 1.3.x -> 2.3.x (2.0.x and 2.1.x not tested and not recommended 
by [the official document](https://spring.io/projects/spring-kafka))
   * [ActiveMQ](https://github.com/apache/activemq) 5.10.0 -> 5.15.4
   * [RabbitMQ](https://www.rabbitmq.com/) 3.x-> 5.x
+  * [Spring-RabbitMQ](https://github.com/spring-projects/spring-amqp) 2.x -> 
4.x
   * [Pulsar](http://pulsar.apache.org) 2.2.x -> 2.9.x
   * [NATS](https://github.com/nats-io/nats.java) 2.14.x -> 2.16.5
   * [ActiveMQ-Artemis](https://github.com/apache/activemq) 2.30.0 -> 2.31.2
diff --git a/test/plugin/scenarios/spring-rabbitmq-scenario/bin/startup.sh 
b/test/plugin/scenarios/spring-rabbitmq-scenario/bin/startup.sh
new file mode 100644
index 0000000000..f98cd90a75
--- /dev/null
+++ b/test/plugin/scenarios/spring-rabbitmq-scenario/bin/startup.sh
@@ -0,0 +1,20 @@
+#!/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 -Dspring.rabbitmq.host=${RABBITMQ_HOST:-rabbitmq-server} -jar 
${agent_opts} ${home}/../libs/spring-rabbitmq-scenario.jar &
diff --git 
a/test/plugin/scenarios/spring-rabbitmq-scenario/config/expectedData.yaml 
b/test/plugin/scenarios/spring-rabbitmq-scenario/config/expectedData.yaml
new file mode 100644
index 0000000000..a9c4a431a2
--- /dev/null
+++ b/test/plugin/scenarios/spring-rabbitmq-scenario/config/expectedData.yaml
@@ -0,0 +1,165 @@
+# 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: spring-rabbitmq-scenario
+  segmentSize: ge 4
+  segments:
+  - segmentId: not null
+    spans:
+    - operationName: HEAD:/spring-rabbitmq-scenario/case/healthcheck
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: Http
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 1
+      isError: false
+      spanType: Entry
+      peer: ''
+      tags:
+      - {key: url, value: 
'http://localhost:8080/spring-rabbitmq-scenario/case/healthcheck'}
+      - {key: http.method, value: HEAD}
+      - {key: http.status_code, value: '200'}
+      skipAnalysis: 'false'
+  - segmentId: not null
+    spans:
+    - operationName: RabbitMQ/Topic/Queue/test/Producer
+      parentSpanId: 0
+      spanId: 1
+      spanLayer: MQ
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 52
+      isError: false
+      spanType: Exit
+      peer: not blank
+      tags:
+      - {key: mq.broker, value: not blank}
+      - {key: mq.queue, value: test}
+      - {key: mq.topic, value: ''}
+      skipAnalysis: 'false'
+    - operationName: RabbitMQ/Topic/Queue/test-batch/Producer
+      parentSpanId: 0
+      spanId: 2
+      spanLayer: MQ
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 52
+      isError: false
+      spanType: Exit
+      peer: not blank
+      tags:
+      - {key: mq.broker, value: not blank}
+      - {key: mq.queue, value: test-batch}
+      - {key: mq.topic, value: ''}
+      skipAnalysis: 'false'
+    - operationName: RabbitMQ/Topic/Queue/test-batch/Producer
+      parentSpanId: 0
+      spanId: 3
+      spanLayer: MQ
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 52
+      isError: false
+      spanType: Exit
+      peer: not blank
+      tags:
+      - {key: mq.broker, value: not blank}
+      - {key: mq.queue, value: test-batch}
+      - {key: mq.topic, value: ''}
+      skipAnalysis: 'false'
+    - operationName: RabbitMQ/Topic/Queue/test-batch/Producer
+      parentSpanId: 0
+      spanId: 4
+      spanLayer: MQ
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 52
+      isError: false
+      spanType: Exit
+      peer: not blank
+      tags:
+      - {key: mq.broker, value: not blank}
+      - {key: mq.queue, value: test-batch}
+      - {key: mq.topic, value: ''}
+      skipAnalysis: 'false'
+    - operationName: GET:/spring-rabbitmq-scenario/case/rabbitmq
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: Http
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 1
+      isError: false
+      spanType: Entry
+      peer: ''
+      tags:
+      - {key: url, value: 
'http://localhost:8080/spring-rabbitmq-scenario/case/rabbitmq'}
+      - {key: http.method, value: GET}
+      - {key: http.status_code, value: '200'}
+      skipAnalysis: 'false'
+  - segmentId: not null
+    spans:
+    - operationName: RabbitMQ/Topic/Queue/test-batch/Consumer
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: MQ
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 53
+      isError: false
+      spanType: Entry
+      peer: not blank
+      tags:
+      - {key: transmission.latency, value: ge 0}
+      - {key: mq.broker, value: not blank}
+      - {key: mq.topic, value: ''}
+      - {key: mq.queue, value: test-batch}
+      - {key: transmission.latency, value: ge 0}
+      - {key: transmission.latency, value: ge 0}
+      refs:
+      - {parentEndpoint: GET:/spring-rabbitmq-scenario/case/rabbitmq, 
networkAddress: not null,
+        refType: CrossProcess, parentSpanId: 2, parentTraceSegmentId: not 
null, parentServiceInstance: not
+          null, parentService: spring-rabbitmq-scenario, traceId: not null}
+      - {parentEndpoint: GET:/spring-rabbitmq-scenario/case/rabbitmq, 
networkAddress: not null,
+        refType: CrossProcess, parentSpanId: 3, parentTraceSegmentId: not 
null, parentServiceInstance: not
+          null, parentService: spring-rabbitmq-scenario, traceId: not null}
+      - {parentEndpoint: GET:/spring-rabbitmq-scenario/case/rabbitmq, 
networkAddress: not null,
+        refType: CrossProcess, parentSpanId: 4, parentTraceSegmentId: not 
null, parentServiceInstance: not
+          null, parentService: spring-rabbitmq-scenario, traceId: not null}
+      skipAnalysis: 'false'
+  - segmentId: not null
+    spans:
+    - operationName: RabbitMQ/Topic/Queue/test/Consumer
+      parentSpanId: -1
+      spanId: 0
+      spanLayer: MQ
+      startTime: nq 0
+      endTime: nq 0
+      componentId: 53
+      isError: false
+      spanType: Entry
+      peer: not blank
+      tags:
+      - {key: transmission.latency, value: ge 0}
+      - {key: mq.broker, value: not blank}
+      - {key: mq.topic, value: ''}
+      - {key: mq.queue, value: test}
+      refs:
+      - {parentEndpoint: GET:/spring-rabbitmq-scenario/case/rabbitmq, 
networkAddress: not null,
+        refType: CrossProcess, parentSpanId: 1, parentTraceSegmentId: not 
null, parentServiceInstance: not
+          null, parentService: spring-rabbitmq-scenario, traceId: not null}
+      skipAnalysis: 'false'
diff --git a/test/plugin/scenarios/spring-rabbitmq-scenario/configuration.yml 
b/test/plugin/scenarios/spring-rabbitmq-scenario/configuration.yml
new file mode 100644
index 0000000000..31cb305bd1
--- /dev/null
+++ b/test/plugin/scenarios/spring-rabbitmq-scenario/configuration.yml
@@ -0,0 +1,33 @@
+# 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/spring-rabbitmq-scenario/case/rabbitmq
+healthCheck: http://localhost:8080/spring-rabbitmq-scenario/case/healthcheck
+startScript: ./bin/startup.sh
+environment:
+  - RABBITMQ_HOST=rabbitmq-server
+depends_on:
+  - rabbitmq-server
+dependencies:
+  rabbitmq-server:
+    image: rabbitmq:3.8.18
+    hostname: rabbitmq-server
+    expose:
+      - 5672
+      - 15672
+    environment:
+      - RABBITMQ_DEFAULT_PASS=admin
+      - RABBITMQ_DEFAULT_USER=admin
+      - RABBITMQ_DEFAULT_VHOST=/
diff --git a/test/plugin/scenarios/spring-rabbitmq-scenario/pom.xml 
b/test/plugin/scenarios/spring-rabbitmq-scenario/pom.xml
new file mode 100644
index 0000000000..0bf98a4869
--- /dev/null
+++ b/test/plugin/scenarios/spring-rabbitmq-scenario/pom.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0";
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.skywalking</groupId>
+    <artifactId>spring-rabbitmq-scenario</artifactId>
+    <version>1.0-SNAPSHOT</version>
+
+    <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.0.0</test.framework.version>
+        <docker.image.version>${test.framework.version}</docker.image.version>
+        <log4j.version>2.19.0</log4j.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-amqp</artifactId>
+            <version>${test.framework.version}</version>
+        </dependency>
+        <!-- Spring Boot-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <version>${test.framework.version}</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                    <groupId>org.springframework.boot</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>${test.framework.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-api</artifactId>
+            <version>${log4j.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.logging.log4j</groupId>
+            <artifactId>log4j-core</artifactId>
+            <version>${log4j.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>spring-rabbitmq-scenario</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${test.framework.version}</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>${maven-compiler-plugin.version}</version>
+                <configuration>
+                    <source>${compiler.version}</source>
+                    <target>${compiler.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>assemble</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                
<descriptor>src/main/assembly/assembly.xml</descriptor>
+                            </descriptors>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
\ No newline at end of file
diff --git 
a/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/assembly/assembly.xml 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/assembly/assembly.xml
new file mode 100644
index 0000000000..0e51e5c531
--- /dev/null
+++ 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/assembly/assembly.xml
@@ -0,0 +1,41 @@
+<?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>${project.build.directory}/spring-rabbitmq-scenario.jar</source>
+            <outputDirectory>./libs</outputDirectory>
+            <fileMode>0775</fileMode>
+        </file>
+    </files>
+</assembly>
diff --git 
a/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/java/org/apache/skywalking/apm/testcase/spring/rabbitmq/Application.java
 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/java/org/apache/skywalking/apm/testcase/spring/rabbitmq/Application.java
new file mode 100644
index 0000000000..9001ed22a9
--- /dev/null
+++ 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/java/org/apache/skywalking/apm/testcase/spring/rabbitmq/Application.java
@@ -0,0 +1,30 @@
+/*
+ * 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.spring.rabbitmq;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class Application {
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+}
diff --git 
a/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/java/org/apache/skywalking/apm/testcase/spring/rabbitmq/config/RabbitMqConfig.java
 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/java/org/apache/skywalking/apm/testcase/spring/rabbitmq/config/RabbitMqConfig.java
new file mode 100644
index 0000000000..a0de5ee428
--- /dev/null
+++ 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/java/org/apache/skywalking/apm/testcase/spring/rabbitmq/config/RabbitMqConfig.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.testcase.spring.rabbitmq.config;
+
+import org.springframework.amqp.core.Queue;
+import 
org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
+import org.springframework.amqp.rabbit.connection.ConnectionFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class RabbitMqConfig {
+
+    @Bean
+    public Queue testQueue() {
+        return new Queue("test", false);
+    }
+
+    @Bean
+    public Queue testBatchQueue() {
+        return new Queue("test-batch", false);
+    }
+
+    @Bean
+    public SimpleRabbitListenerContainerFactory 
batchRabbitListenerContainerFactory(
+        ConnectionFactory connectionFactory) {
+        SimpleRabbitListenerContainerFactory factory = new 
SimpleRabbitListenerContainerFactory();
+        factory.setConnectionFactory(connectionFactory);
+        // Enable batch listening mode
+        factory.setBatchListener(true);
+        factory.setConsumerBatchEnabled(true);
+        // Set batch size
+        factory.setBatchSize(3);
+        factory.setPrefetchCount(3);
+        factory.setReceiveTimeout(3000L);
+        return factory;
+    }
+}
diff --git 
a/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/java/org/apache/skywalking/apm/testcase/spring/rabbitmq/controller/CaseController.java
 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/java/org/apache/skywalking/apm/testcase/spring/rabbitmq/controller/CaseController.java
new file mode 100644
index 0000000000..e143c51bf9
--- /dev/null
+++ 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/java/org/apache/skywalking/apm/testcase/spring/rabbitmq/controller/CaseController.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.apm.testcase.spring.rabbitmq.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.core.MessageBuilder;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.amqp.rabbit.core.RabbitTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/case")
+public class CaseController {
+
+    private static final Logger LOGGER = 
LogManager.getLogger(CaseController.class);
+
+    private static final String QUEUE_NAME = "test";
+    private static final String BATCH_QUEUE_NAME = "test-batch";
+
+    private static final String MESSAGE = "rabbitmq-testcase";
+
+    @Autowired
+    private RabbitTemplate rabbitTemplate;
+
+    @RequestMapping("/rabbitmq")
+    @ResponseBody
+    public String send() {
+        LOGGER.info("Message being published -------------->" + MESSAGE);
+        rabbitTemplate.convertAndSend(QUEUE_NAME, MESSAGE);
+        LOGGER.info("Message has been published-------------->" + MESSAGE);
+
+        // Also send batch messages to test batch consumption
+        LOGGER.info("Sending batch messages --------------");
+        List<Message> messages = new ArrayList<>();
+        for (int i = 0; i < 3; i++) {
+            Message message = MessageBuilder.withBody(("batch-message-" + 
i).getBytes()).build();
+            messages.add(message);
+        }
+        for (Message message : messages) {
+            rabbitTemplate.send(BATCH_QUEUE_NAME, message);
+        }
+        LOGGER.info("Batch messages have been published--------------");
+
+        return "Success";
+    }
+
+    @RabbitListener(queues = QUEUE_NAME)
+    public void consumer(String message) {
+        LOGGER.info("Message Consumer received-------------->" + message);
+    }
+
+    @RabbitListener(queues = BATCH_QUEUE_NAME, containerFactory = 
"batchRabbitListenerContainerFactory")
+    public void batchConsumer(List<String> messages) {
+        LOGGER.info("Batch Consumer received " + messages.size() + " messages: 
" + messages);
+    }
+
+    @RequestMapping("/healthcheck")
+    public String healthCheck() {
+        return "Success";
+    }
+}
diff --git 
a/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/resources/application.yml
 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/resources/application.yml
new file mode 100644
index 0000000000..5b93e6c91a
--- /dev/null
+++ 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/resources/application.yml
@@ -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.
+#
+#
+server:
+  port: 8080
+  servlet:
+    context-path: /spring-rabbitmq-scenario
+
+spring:
+  rabbitmq:
+    host: ${RABBITMQ_HOST:127.0.0.1}
+    port: 5672
+    username: admin
+    password: admin
+    virtual-host: /
diff --git 
a/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/resources/log4j2.xml 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/resources/log4j2.xml
new file mode 100644
index 0000000000..565fda00e0
--- /dev/null
+++ 
b/test/plugin/scenarios/spring-rabbitmq-scenario/src/main/resources/log4j2.xml
@@ -0,0 +1,31 @@
+<?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.
+  ~
+  -->
+
+<Configuration status="WARN">
+    <Appenders>
+        <Console name="Console" target="SYSTEM_ERR">
+            <PatternLayout charset="UTF-8" pattern="[%d{yyyy-MM-dd 
HH:mm:ss:SSS}] [%p] - %l - %m%n"/>
+        </Console>
+    </Appenders>
+    <Loggers>
+        <Root level="info">
+            <AppenderRef ref="Console"/>
+        </Root>
+    </Loggers>
+</Configuration>
diff --git 
a/test/plugin/scenarios/spring-rabbitmq-scenario/support-version.list 
b/test/plugin/scenarios/spring-rabbitmq-scenario/support-version.list
new file mode 100644
index 0000000000..8c67d6f4a8
--- /dev/null
+++ b/test/plugin/scenarios/spring-rabbitmq-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.0
+4.0.0
\ No newline at end of file

Reply via email to