You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2019/03/27 21:14:44 UTC

[incubator-skywalking] branch master updated: Support dubbo 2.7.x (#2365)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 4139389  Support dubbo 2.7.x (#2365)
4139389 is described below

commit 413938916821aa6c3906e05e852c7871d2aa00ef
Author: kezhenxu94 <ke...@163.com>
AuthorDate: Thu Mar 28 05:14:37 2019 +0800

    Support dubbo 2.7.x (#2365)
    
    * support dubbo 2.7.x
    
    * updated
    
    * rename package
    
    * rename package
    
    * fix UT
    
    * rename class
---
 .../dubbo-2.7.x-conflict-patch/pom.xml             |  44 ++++
 .../asf/dubbo/patch/MakeWrapperInterceptor.java    | 272 +++++++++++++++++++++
 .../asf/dubbo/patch/WrapperInstrumentation.java    |  59 +++++
 .../src/main/resources/skywalking-plugin.def       |  17 ++
 .../apm-sdk-plugin/dubbo-2.7.x-plugin/pom.xml      |  46 ++++
 .../apm/plugin/asf/dubbo/DubboInstrumentation.java |  68 ++++++
 .../apm/plugin/asf/dubbo/DubboInterceptor.java     | 155 ++++++++++++
 .../src/main/resources/skywalking-plugin.def       |  17 ++
 .../dubbo/ContextManagerExtendOverrideService.java |  29 +++
 .../apm/plugin/dubbo/DubboInterceptorTest.java     | 225 +++++++++++++++++
 .../apm/plugin/dubbo/PluginBootService.java        |  42 ++++
 ...ache.skywalking.apm.agent.core.boot.BootService |  20 ++
 apm-sniffer/apm-sdk-plugin/pom.xml                 |   2 +
 13 files changed, 996 insertions(+)

diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/pom.xml b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/pom.xml
new file mode 100644
index 0000000..e5da821
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/pom.xml
@@ -0,0 +1,44 @@
+<?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>apm-sdk-plugin</artifactId>
+        <groupId>org.apache.skywalking</groupId>
+        <version>6.1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dubbo-2.7.x-conflict-patch</artifactId>
+
+    <name>apm-dubbo-2.7.x-conflict-path</name>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <dubbo.version>2.7.0</dubbo.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo</artifactId>
+            <version>${dubbo.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/patch/MakeWrapperInterceptor.java b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/patch/MakeWrapperInterceptor.java
new file mode 100644
index 0000000..7e8b5e9
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/patch/MakeWrapperInterceptor.java
@@ -0,0 +1,272 @@
+/*
+ * 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.asf.dubbo.patch;
+
+import org.apache.dubbo.common.bytecode.ClassGenerator;
+import org.apache.dubbo.common.bytecode.NoSuchPropertyException;
+import org.apache.dubbo.common.bytecode.Wrapper;
+import org.apache.dubbo.common.utils.ClassHelper;
+import org.apache.dubbo.common.utils.ReflectUtils;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Matcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.StaticMethodsAroundInterceptor;
+
+public class MakeWrapperInterceptor implements StaticMethodsAroundInterceptor {
+
+    private static final AtomicLong WRAPPER_CLASS_COUNTER = new AtomicLong(0);
+
+    @Override
+    public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
+        MethodInterceptResult result) {
+        Class wrapperClass = (Class<?>)allArguments[0];
+        if (EnhancedInstance.class.isAssignableFrom(wrapperClass)) {
+            result.defineReturnValue(makeWrapper(wrapperClass));
+        }
+    }
+
+    @Override public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
+        Object ret) {
+        return ret;
+    }
+
+    @Override
+    public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
+        Throwable t) {
+    }
+
+    private static Wrapper makeWrapper(Class<?> c) {
+        if (c.isPrimitive())
+            throw new IllegalArgumentException("Can not create wrapper for primitive type: " + c);
+
+        String name = c.getName();
+        ClassLoader cl = ClassHelper.getClassLoader(c);
+
+        StringBuilder c1 = new StringBuilder("public void setPropertyValue(Object o, String n, Object v){ ");
+        StringBuilder c2 = new StringBuilder("public Object getPropertyValue(Object o, String n){ ");
+        StringBuilder c3 = new StringBuilder("public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws " + InvocationTargetException.class.getName() + "{ ");
+
+        c1.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
+        c2.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
+        c3.append(name).append(" w; try{ w = ((").append(name).append(")$1); }catch(Throwable e){ throw new IllegalArgumentException(e); }");
+
+        Map<String, Class<?>> pts = new HashMap<String, Class<?>>(); // <property name, property types>
+        Map<String, Method> ms = new LinkedHashMap<String, Method>(); // <method desc, Method instance>
+        List<String> mns = new ArrayList<String>(); // method names.
+        List<String> dmns = new ArrayList<String>(); // declaring method names.
+
+        // get all public field.
+        for (Field f : c.getFields()) {
+            String fn = f.getName();
+            Class<?> ft = f.getType();
+            if (Modifier.isStatic(f.getModifiers()) || Modifier.isTransient(f.getModifiers()))
+                continue;
+
+            c1.append(" if( $2.equals(\"").append(fn).append("\") ){ w.").append(fn).append("=").append(arg(ft, "$3")).append("; return; }");
+            c2.append(" if( $2.equals(\"").append(fn).append("\") ){ return ($w)w.").append(fn).append("; }");
+            pts.put(fn, ft);
+        }
+
+        Method[] methods = c.getMethods();
+        // get all public method.
+        boolean hasMethod = hasMethods(methods);
+        if (hasMethod) {
+            c3.append(" try{");
+        }
+        for (Method m : methods) {
+            // ignore Object's method
+            // ignore EnhanceInstance's method
+            if (m.getDeclaringClass() == Object.class || "getSkyWalkingDynamicField".equals(m.getName()) || "setSkyWalkingDynamicField".equals(m.getName())) {
+                continue;
+            }
+
+            String mn = m.getName();
+            c3.append(" if( \"").append(mn).append("\".equals( $2 ) ");
+            int len = m.getParameterTypes().length;
+            c3.append(" && ").append(" $3.length == ").append(len);
+
+            boolean override = false;
+            for (Method m2 : methods) {
+                if (m != m2 && m.getName().equals(m2.getName())) {
+                    override = true;
+                    break;
+                }
+            }
+            if (override) {
+                if (len > 0) {
+                    for (int l = 0; l < len; l++) {
+                        c3.append(" && ").append(" $3[").append(l).append("].getName().equals(\"")
+                            .append(m.getParameterTypes()[l].getName()).append("\")");
+                    }
+                }
+            }
+
+            c3.append(" ) { ");
+
+            if (m.getReturnType() == Void.TYPE)
+                c3.append(" w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");").append(" return null;");
+            else
+                c3.append(" return ($w)w.").append(mn).append('(').append(args(m.getParameterTypes(), "$4")).append(");");
+
+            c3.append(" }");
+
+            mns.add(mn);
+            if (m.getDeclaringClass() == c)
+                dmns.add(mn);
+            ms.put(ReflectUtils.getDesc(m), m);
+        }
+        if (hasMethod) {
+            c3.append(" } catch(Throwable e) { ");
+            c3.append("     throw new java.lang.reflect.InvocationTargetException(e); ");
+            c3.append(" }");
+        }
+
+        c3.append(" throw new " + NoSuchMethodException.class.getName() + "(\"Not found method \\\"\"+$2+\"\\\" in class " + c.getName() + ".\"); }");
+
+        // deal with get/set method.
+        Matcher matcher;
+        for (Map.Entry<String, Method> entry : ms.entrySet()) {
+            String md = entry.getKey();
+            Method method = (Method)entry.getValue();
+            if ((matcher = ReflectUtils.GETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
+                String pn = propertyName(matcher.group(1));
+                c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
+                pts.put(pn, method.getReturnType());
+            } else if ((matcher = ReflectUtils.IS_HAS_CAN_METHOD_DESC_PATTERN.matcher(md)).matches()) {
+                String pn = propertyName(matcher.group(1));
+                c2.append(" if( $2.equals(\"").append(pn).append("\") ){ return ($w)w.").append(method.getName()).append("(); }");
+                pts.put(pn, method.getReturnType());
+            } else if ((matcher = ReflectUtils.SETTER_METHOD_DESC_PATTERN.matcher(md)).matches()) {
+                Class<?> pt = method.getParameterTypes()[0];
+                String pn = propertyName(matcher.group(1));
+                c1.append(" if( $2.equals(\"").append(pn).append("\") ){ w.").append(method.getName()).append("(").append(arg(pt, "$3")).append("); return; }");
+                pts.put(pn, pt);
+            }
+        }
+        c1.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
+        c2.append(" throw new " + NoSuchPropertyException.class.getName() + "(\"Not found property \\\"\"+$2+\"\\\" filed or setter method in class " + c.getName() + ".\"); }");
+
+        // make class
+        long id = WRAPPER_CLASS_COUNTER.getAndIncrement();
+        ClassGenerator cc = ClassGenerator.newInstance(cl);
+        cc.setClassName((Modifier.isPublic(c.getModifiers()) ? Wrapper.class.getName() + "_swEnhance" : c.getName() + "$sw$_swEnhance") + id);
+        cc.setSuperClass(Wrapper.class);
+
+        cc.addDefaultConstructor();
+        cc.addField("public static String[] pns;"); // property name array.
+        cc.addField("public static " + Map.class.getName() + " pts;"); // property type map.
+        cc.addField("public static String[] mns;"); // all method name array.
+        cc.addField("public static String[] dmns;"); // declared method name array.
+        for (int i = 0, len = ms.size(); i < len; i++)
+            cc.addField("public static Class[] mts" + i + ";");
+
+        cc.addMethod("public String[] getPropertyNames(){ return pns; }");
+        cc.addMethod("public boolean hasProperty(String n){ return pts.containsKey($1); }");
+        cc.addMethod("public Class getPropertyType(String n){ return (Class)pts.get($1); }");
+        cc.addMethod("public String[] getMethodNames(){ return mns; }");
+        cc.addMethod("public String[] getDeclaredMethodNames(){ return dmns; }");
+        cc.addMethod(c1.toString());
+        cc.addMethod(c2.toString());
+        cc.addMethod(c3.toString());
+
+        try {
+            Class<?> wc = cc.toClass();
+            // setup static field.
+            wc.getField("pts").set(null, pts);
+            wc.getField("pns").set(null, pts.keySet().toArray(new String[0]));
+            wc.getField("mns").set(null, mns.toArray(new String[0]));
+            wc.getField("dmns").set(null, dmns.toArray(new String[0]));
+            int ix = 0;
+            for (Method m : ms.values())
+                wc.getField("mts" + ix++).set(null, m.getParameterTypes());
+            return (Wrapper)wc.newInstance();
+        } catch (RuntimeException e) {
+            throw e;
+        } catch (Throwable e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } finally {
+            cc.release();
+            ms.clear();
+            mns.clear();
+            dmns.clear();
+        }
+    }
+
+    private static String args(Class<?>[] cs, String name) {
+        int len = cs.length;
+        if (len == 0)
+            return "";
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < len; i++) {
+            if (i > 0)
+                sb.append(',');
+            sb.append(arg(cs[i], name + "[" + i + "]"));
+        }
+        return sb.toString();
+    }
+
+    private static String propertyName(String pn) {
+        return pn.length() == 1 || Character.isLowerCase(pn.charAt(1)) ? Character.toLowerCase(pn.charAt(0)) + pn.substring(1) : pn;
+    }
+
+    private static boolean hasMethods(Method[] methods) {
+        if (methods == null || methods.length == 0) {
+            return false;
+        }
+        for (Method m : methods) {
+            if (m.getDeclaringClass() != Object.class) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static String arg(Class<?> cl, String name) {
+        if (cl.isPrimitive()) {
+            if (cl == Boolean.TYPE)
+                return "((Boolean)" + name + ").booleanValue()";
+            if (cl == Byte.TYPE)
+                return "((Byte)" + name + ").byteValue()";
+            if (cl == Character.TYPE)
+                return "((Character)" + name + ").charValue()";
+            if (cl == Double.TYPE)
+                return "((Number)" + name + ").doubleValue()";
+            if (cl == Float.TYPE)
+                return "((Number)" + name + ").floatValue()";
+            if (cl == Integer.TYPE)
+                return "((Number)" + name + ").intValue()";
+            if (cl == Long.TYPE)
+                return "((Number)" + name + ").longValue()";
+            if (cl == Short.TYPE)
+                return "((Number)" + name + ").shortValue()";
+            throw new RuntimeException("Unknown primitive type: " + cl.getName());
+        }
+        return "(" + ReflectUtils.getName(cl) + ")" + name;
+    }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/patch/WrapperInstrumentation.java b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/patch/WrapperInstrumentation.java
new file mode 100644
index 0000000..09af65e
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/patch/WrapperInstrumentation.java
@@ -0,0 +1,59 @@
+/*
+ * 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.asf.dubbo.patch;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.StaticMethodsInterceptPoint;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassStaticMethodsEnhancePluginDefine;
+import org.apache.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.apache.skywalking.apm.agent.core.plugin.match.NameMatch.byName;
+
+/**
+ * The dubbo conflict plugin resolver the problem about the wrapper class generated by Dubbo core cannot be compiled successfully. As we known,
+ * The wrapper class traverses all the methods. In usual, it works unless this
+ * class has been enhanced by Skywalking. The javasist cannot found the `EnhanceInstance` method when generate.
+ *
+ * The plugin excludes {@link org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance}
+ * methods to ensure the correct compilation of the code.
+ */
+public class WrapperInstrumentation extends ClassStaticMethodsEnhancePluginDefine {
+    @Override protected StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() {
+        return new StaticMethodsInterceptPoint[] {
+            new StaticMethodsInterceptPoint() {
+                @Override public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                    return named("makeWrapper");
+                }
+
+                @Override public String getMethodsInterceptor() {
+                    return "org.apache.skywalking.apm.plugin.dubbo.patch.MakeWrapperInterceptor";
+                }
+
+                @Override public boolean isOverrideArgs() {
+                    return false;
+                }
+            }
+        };
+    }
+
+    @Override protected ClassMatch enhanceClass() {
+        return byName("org.apache.dubbo.common.bytecode.Wrapper");
+    }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000..d26e43a
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-conflict-patch/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.
+
+dubbo=org.apache.skywalking.apm.plugin.asf.dubbo.patch.WrapperInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/pom.xml
new file mode 100644
index 0000000..d9d30c7
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/pom.xml
@@ -0,0 +1,46 @@
+<!--
+  ~ 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>apm-sdk-plugin</artifactId>
+        <groupId>org.apache.skywalking</groupId>
+        <version>6.1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>apm-dubbo-2.7.x-plugin</artifactId>
+    <packaging>jar</packaging>
+
+    <name>dubbo-2.7.x-plugin</name>
+    <url>http://maven.apache.org</url>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <dubbo.version>2.7.0</dubbo.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo</artifactId>
+            <version>${dubbo.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/DubboInstrumentation.java b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/DubboInstrumentation.java
new file mode 100644
index 0000000..1bde0b4
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/DubboInstrumentation.java
@@ -0,0 +1,68 @@
+/*
+ * 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.asf.dubbo;
+
+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 org.apache.skywalking.apm.agent.core.plugin.match.NameMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+
+public class DubboInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+    private static final String ENHANCE_CLASS = "org.apache.dubbo.monitor.support.MonitorFilter";
+
+    private static final String INTERCEPT_CLASS = "org.apache.skywalking.apm.plugin.asf.dubbo.DubboInterceptor";
+
+    @Override
+    protected ClassMatch enhanceClass() {
+        return NameMatch.byName(ENHANCE_CLASS);
+    }
+
+    @Override
+    protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+        return null;
+    }
+
+    @Override
+    protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+        return new InstanceMethodsInterceptPoint[] {
+            new InstanceMethodsInterceptPoint() {
+                @Override
+                public ElementMatcher<MethodDescription> getMethodsMatcher() {
+                    return named("invoke");
+                }
+
+                @Override
+                public String getMethodsInterceptor() {
+                    return INTERCEPT_CLASS;
+                }
+
+                @Override
+                public boolean isOverrideArgs() {
+                    return false;
+                }
+            }
+        };
+    }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/DubboInterceptor.java b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/DubboInterceptor.java
new file mode 100644
index 0000000..6167179
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/main/java/org/apache/skywalking/apm/plugin/asf/dubbo/DubboInterceptor.java
@@ -0,0 +1,155 @@
+/*
+ * 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.asf.dubbo;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcContext;
+import java.lang.reflect.Method;
+import org.apache.skywalking.apm.agent.core.context.ContextCarrier;
+import org.apache.skywalking.apm.agent.core.context.tag.Tags;
+import org.apache.skywalking.apm.agent.core.context.CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.ContextManager;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.network.trace.component.ComponentsDefine;
+
+/**
+ * {@link DubboInterceptor} define how to enhance class {@link org.apache.dubbo.monitor.support.MonitorFilter#invoke(Invoker,
+ * Invocation)}. the trace context transport to the provider side by {@link RpcContext#attachments}.but all the version
+ * of dubbo framework below 2.8.3 don't support {@link RpcContext#attachments}, we support another way to support it.
+ *
+ */
+public class DubboInterceptor implements InstanceMethodsAroundInterceptor {
+    /**
+     * <h2>Consumer:</h2> The serialized trace context data will
+     * inject to the {@link RpcContext#attachments} for transport to provider side.
+     * <p>
+     * <h2>Provider:</h2> The serialized trace context data will extract from
+     * {@link RpcContext#attachments}. current trace segment will ref if the serialize context data is not null.
+     */
+    @Override
+    public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+        Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+        Invoker invoker = (Invoker)allArguments[0];
+        Invocation invocation = (Invocation)allArguments[1];
+        RpcContext rpcContext = RpcContext.getContext();
+        boolean isConsumer = rpcContext.isConsumerSide();
+        URL requestURL = invoker.getUrl();
+
+        AbstractSpan span;
+
+        final String host = requestURL.getHost();
+        final int port = requestURL.getPort();
+        if (isConsumer) {
+            final ContextCarrier contextCarrier = new ContextCarrier();
+            span = ContextManager.createExitSpan(generateOperationName(requestURL, invocation), contextCarrier, host + ":" + port);
+            //invocation.getAttachments().put("contextData", contextDataStr);
+            //@see https://github.com/alibaba/dubbo/blob/dubbo-2.5.3/dubbo-rpc/dubbo-rpc-api/src/main/java/com/alibaba/dubbo/rpc/RpcInvocation.java#L154-L161
+            CarrierItem next = contextCarrier.items();
+            while (next.hasNext()) {
+                next = next.next();
+                rpcContext.getAttachments().put(next.getHeadKey(), next.getHeadValue());
+            }
+        } else {
+            ContextCarrier contextCarrier = new ContextCarrier();
+            CarrierItem next = contextCarrier.items();
+            while (next.hasNext()) {
+                next = next.next();
+                next.setHeadValue(rpcContext.getAttachment(next.getHeadKey()));
+            }
+
+            span = ContextManager.createEntrySpan(generateOperationName(requestURL, invocation), contextCarrier);
+        }
+
+        Tags.URL.set(span, generateRequestURL(requestURL, invocation));
+        span.setComponent(ComponentsDefine.DUBBO);
+        SpanLayer.asRPCFramework(span);
+    }
+
+    @Override
+    public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments,
+        Class<?>[] argumentsTypes, Object ret) throws Throwable {
+        Result result = (Result)ret;
+        if (result != null && result.getException() != null) {
+            dealException(result.getException());
+        }
+
+        ContextManager.stopSpan();
+        return ret;
+    }
+
+    @Override
+    public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments,
+        Class<?>[] argumentsTypes, Throwable t) {
+        dealException(t);
+    }
+
+    /**
+     * Log the throwable, which occurs in Dubbo RPC service.
+     */
+    private void dealException(Throwable throwable) {
+        AbstractSpan span = ContextManager.activeSpan();
+        span.errorOccurred();
+        span.log(throwable);
+    }
+
+    /**
+     * Format operation name. e.g. org.apache.skywalking.apm.plugin.test.Test.test(String)
+     *
+     * @return operation name.
+     */
+    private String generateOperationName(URL requestURL, Invocation invocation) {
+        StringBuilder operationName = new StringBuilder();
+        operationName.append(requestURL.getPath());
+        operationName.append("." + invocation.getMethodName() + "(");
+        for (Class<?> classes : invocation.getParameterTypes()) {
+            operationName.append(classes.getSimpleName() + ",");
+        }
+
+        if (invocation.getParameterTypes().length > 0) {
+            operationName.delete(operationName.length() - 1, operationName.length());
+        }
+
+        operationName.append(")");
+
+        return operationName.toString();
+    }
+
+    /**
+     * Format request url.
+     * e.g. dubbo://127.0.0.1:20880/org.apache.skywalking.apm.plugin.test.Test.test(String).
+     *
+     * @return request url.
+     */
+    private String generateRequestURL(URL url, Invocation invocation) {
+        StringBuilder requestURL = new StringBuilder();
+        requestURL.append(url.getProtocol() + "://");
+        requestURL.append(url.getHost());
+        requestURL.append(":" + url.getPort() + "/");
+        requestURL.append(generateOperationName(url, invocation));
+        return requestURL.toString();
+    }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000..cd31eec
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-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.
+
+dubbo=org.apache.skywalking.apm.plugin.asf.dubbo.DubboInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/dubbo/ContextManagerExtendOverrideService.java b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/dubbo/ContextManagerExtendOverrideService.java
new file mode 100644
index 0000000..9a2cacc
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/dubbo/ContextManagerExtendOverrideService.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.plugin.dubbo;
+
+import org.apache.skywalking.apm.agent.core.boot.OverrideImplementor;
+import org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService;
+
+/**
+ * @author wusheng
+ */
+@OverrideImplementor(ContextManagerExtendService.class)
+public class ContextManagerExtendOverrideService extends ContextManagerExtendService {
+}
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/dubbo/DubboInterceptorTest.java b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/dubbo/DubboInterceptorTest.java
new file mode 100644
index 0000000..f31ed73
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/dubbo/DubboInterceptorTest.java
@@ -0,0 +1,225 @@
+/*
+ * 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.dubbo;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcContext;
+import java.util.List;
+import org.apache.skywalking.apm.agent.core.boot.ServiceManager;
+import org.apache.skywalking.apm.agent.core.conf.Config;
+import org.apache.skywalking.apm.agent.core.context.ContextManagerExtendService;
+import org.apache.skywalking.apm.agent.core.context.SW3CarrierItem;
+import org.apache.skywalking.apm.agent.core.context.trace.AbstractTracingSpan;
+import org.apache.skywalking.apm.agent.core.context.trace.LogDataEntity;
+import org.apache.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegment;
+import org.apache.skywalking.apm.agent.core.context.trace.TraceSegmentRef;
+import org.apache.skywalking.apm.agent.core.context.util.TagValuePair;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.apache.skywalking.apm.agent.test.helper.SegmentHelper;
+import org.apache.skywalking.apm.agent.test.helper.SegmentRefHelper;
+import org.apache.skywalking.apm.agent.test.helper.SpanHelper;
+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.apache.skywalking.apm.plugin.asf.dubbo.DubboInterceptor;
+import org.hamcrest.CoreMatchers;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.powermock.modules.junit4.PowerMockRunnerDelegate;
+import org.springframework.util.Assert;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.powermock.api.mockito.PowerMockito.when;
+
+@RunWith(PowerMockRunner.class)
+@PowerMockRunnerDelegate(TracingSegmentRunner.class)
+@PrepareForTest({RpcContext.class})
+public class DubboInterceptorTest {
+
+    @SegmentStoragePoint
+    private SegmentStorage segmentStorage;
+
+    @Rule
+    public AgentServiceRule agentServiceRule = new AgentServiceRule();
+
+    @Mock
+    private EnhancedInstance enhancedInstance;
+
+    private DubboInterceptor dubboInterceptor;
+
+    @Mock
+    private RpcContext rpcContext;
+    @Mock
+    private Invoker invoker;
+    @Mock
+    private Invocation invocation;
+    @Mock
+    private MethodInterceptResult methodInterceptResult;
+    @Mock
+    private Result result;
+
+    private Object[] allArguments;
+    private Class[] argumentTypes;
+
+    @Before
+    public void setUp() throws Exception {
+        Config.Agent.ACTIVE_V1_HEADER = true;
+        dubboInterceptor = new DubboInterceptor();
+
+        PowerMockito.mockStatic(RpcContext.class);
+
+        when(invoker.getUrl()).thenReturn(URL.valueOf("dubbo://127.0.0.1:20880/org.apache.skywalking.apm.test.TestDubboService"));
+        when(invocation.getMethodName()).thenReturn("test");
+        when(invocation.getParameterTypes()).thenReturn(new Class[] {String.class});
+        when(invocation.getArguments()).thenReturn(new Object[] {"abc"});
+        PowerMockito.when(RpcContext.getContext()).thenReturn(rpcContext);
+        when(rpcContext.isConsumerSide()).thenReturn(true);
+        allArguments = new Object[] {invoker, invocation};
+        argumentTypes = new Class[] {invoker.getClass(), invocation.getClass()};
+        Config.Agent.SERVICE_NAME = "DubboTestCases-APP";
+    }
+
+    @After
+    public void clear() {
+        Config.Agent.ACTIVE_V1_HEADER = false;
+    }
+
+    @Test
+    public void testServiceFromPlugin() {
+        PluginBootService service = ServiceManager.INSTANCE.findService(PluginBootService.class);
+
+        Assert.notNull(service);
+    }
+
+    @Test
+    public void testServiceOverrideFromPlugin() {
+        ContextManagerExtendService service = ServiceManager.INSTANCE.findService(ContextManagerExtendService.class);
+
+        Assert.isInstanceOf(ContextManagerExtendOverrideService.class, service);
+    }
+
+    @Test
+    public void testConsumerWithAttachment() throws Throwable {
+        dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
+        dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
+
+        assertThat(segmentStorage.getTraceSegments().size(), is(1));
+        TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+        List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
+        assertThat(spans.size(), is(1));
+        assertConsumerSpan(spans.get(0));
+    }
+
+    @Test
+    public void testConsumerWithException() throws Throwable {
+        dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
+        dubboInterceptor.handleMethodException(enhancedInstance, null, allArguments, argumentTypes, new RuntimeException());
+        dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
+        assertThat(segmentStorage.getTraceSegments().size(), is(1));
+        TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+        assertConsumerTraceSegmentInErrorCase(traceSegment);
+    }
+
+    @Test
+    public void testConsumerWithResultHasException() throws Throwable {
+        when(result.getException()).thenReturn(new RuntimeException());
+
+        dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
+        dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
+
+        assertThat(segmentStorage.getTraceSegments().size(), is(1));
+        TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+        assertConsumerTraceSegmentInErrorCase(traceSegment);
+    }
+
+    @Test
+    public void testProviderWithAttachment() throws Throwable {
+        when(rpcContext.isConsumerSide()).thenReturn(false);
+        when(rpcContext.getAttachment(SW3CarrierItem.HEADER_NAME)).thenReturn("1.323.4433|3|1|1|#192.168.1.8 :18002|#/portal/|#/testEntrySpan|#AQA*#AQA*Et0We0tQNQA*");
+
+        dubboInterceptor.beforeMethod(enhancedInstance, null, allArguments, argumentTypes, methodInterceptResult);
+        dubboInterceptor.afterMethod(enhancedInstance, null, allArguments, argumentTypes, result);
+        assertProvider();
+    }
+
+    private void assertConsumerTraceSegmentInErrorCase(
+        TraceSegment traceSegment) {
+        List<AbstractTracingSpan> spans = SegmentHelper.getSpans(traceSegment);
+        assertThat(spans.size(), is(1));
+        assertConsumerSpan(spans.get(0));
+        AbstractTracingSpan span = spans.get(0);
+        assertThat(SpanHelper.getLogs(span).size(), is(1));
+        assertErrorLog(SpanHelper.getLogs(span).get(0));
+    }
+
+    private void assertErrorLog(LogDataEntity logData) {
+        assertThat(logData.getLogs().size(), is(4));
+        assertThat(logData.getLogs().get(0).getValue(), CoreMatchers.<Object>is("error"));
+        assertThat(logData.getLogs().get(1).getValue(), CoreMatchers.<Object>is(RuntimeException.class.getName()));
+        assertNull(logData.getLogs().get(2).getValue());
+    }
+
+    private void assertProvider() {
+        TraceSegment traceSegment = segmentStorage.getTraceSegments().get(0);
+        assertThat(SegmentHelper.getSpans(traceSegment).size(), is(1));
+        assertProviderSpan(SegmentHelper.getSpans(traceSegment).get(0));
+        assertTraceSegmentRef(traceSegment.getRefs().get(0));
+    }
+
+    private void assertTraceSegmentRef(TraceSegmentRef actual) {
+        assertThat(SegmentRefHelper.getSpanId(actual), is(3));
+        assertThat(SegmentRefHelper.getEntryServiceInstanceId(actual), is(1));
+        assertThat(SegmentRefHelper.getTraceSegmentId(actual).toString(), is("1.323.4433"));
+    }
+
+    private void assertProviderSpan(AbstractTracingSpan span) {
+        assertCommonsAttribute(span);
+        assertTrue(span.isEntry());
+    }
+
+    private void assertConsumerSpan(AbstractTracingSpan span) {
+        assertCommonsAttribute(span);
+        assertTrue(span.isExit());
+    }
+
+    private void assertCommonsAttribute(AbstractTracingSpan span) {
+        List<TagValuePair> tags = SpanHelper.getTags(span);
+        assertThat(tags.size(), is(1));
+        assertThat(SpanHelper.getLayer(span), CoreMatchers.is(SpanLayer.RPC_FRAMEWORK));
+        assertThat(SpanHelper.getComponentId(span), is(3));
+        assertThat(tags.get(0).getValue(), is("dubbo://127.0.0.1:20880/org.apache.skywalking.apm.test.TestDubboService.test(String)"));
+        assertThat(span.getOperationName(), is("org.apache.skywalking.apm.test.TestDubboService.test(String)"));
+    }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/dubbo/PluginBootService.java b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/dubbo/PluginBootService.java
new file mode 100644
index 0000000..b91e137
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/java/org/apache/skywalking/apm/plugin/dubbo/PluginBootService.java
@@ -0,0 +1,42 @@
+/*
+ * 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.dubbo;
+
+import org.apache.skywalking.apm.agent.core.boot.BootService;
+
+/**
+ * @author wusheng
+ */
+public class PluginBootService implements BootService {
+    @Override public void prepare() throws Throwable {
+
+    }
+
+    @Override public void boot() throws Throwable {
+
+    }
+
+    @Override public void onComplete() throws Throwable {
+
+    }
+
+    @Override public void shutdown() throws Throwable {
+
+    }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/resources/META-INF/services/org.apache.skywalking.apm.agent.core.boot.BootService b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/resources/META-INF/services/org.apache.skywalking.apm.agent.core.boot.BootService
new file mode 100644
index 0000000..ccf7067
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/dubbo-2.7.x-plugin/src/test/resources/META-INF/services/org.apache.skywalking.apm.agent.core.boot.BootService
@@ -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.
+#
+#
+
+org.apache.skywalking.apm.plugin.dubbo.PluginBootService
+org.apache.skywalking.apm.plugin.dubbo.ContextManagerExtendOverrideService
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index 63e97a7..b2f0023 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -67,6 +67,8 @@
         <module>rabbitmq-5.x-plugin</module>
         <module>dubbo-conflict-patch</module>
         <module>canal-1.x-plugin</module>
+        <module>dubbo-2.7.x-plugin</module>
+        <module>dubbo-2.7.x-conflict-patch</module>
     </modules>
     <packaging>pom</packaging>