diff --git a/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java b/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java
index 912efa40c4439ebd2d7e3b739432c8ed4c1dd109..d70e567877a066bbde8171f7e3422d573aa2fce4 100644
--- a/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java
+++ b/apm-network/src/main/java/org/skywalking/apm/network/trace/component/ComponentsDefine.java
@@ -31,6 +31,8 @@ public class ComponentsDefine {
public static final OfficialComponent OKHTTP = new OfficialComponent(12, "OKHttp");
+ public static final OfficialComponent REST_TEMPLATE = new OfficialComponent(13, "RestTemplate");
+
private static ComponentsDefine instance = new ComponentsDefine();
private String[] components;
@@ -40,7 +42,7 @@ public class ComponentsDefine {
}
public ComponentsDefine() {
- components = new String[13];
+ components = new String[14];
addComponent(TOMCAT);
addComponent(HTTPCLIENT);
addComponent(DUBBO);
@@ -53,6 +55,7 @@ public class ComponentsDefine {
addComponent(RESIN);
addComponent(FEIGN);
addComponent(OKHTTP);
+ addComponent(REST_TEMPLATE);
}
private void addComponent(OfficialComponent component) {
diff --git a/apm-sniffer/apm-agent/pom.xml b/apm-sniffer/apm-agent/pom.xml
index b07bef698acdf520f7322bc90fc9427eb7430531..11c5388f879afc3a3446f2c93ac45634d50304e2 100644
--- a/apm-sniffer/apm-agent/pom.xml
+++ b/apm-sniffer/apm-agent/pom.xml
@@ -80,6 +80,16 @@
apm-feign-default-http-9.x-plugin
${project.version}
+
+ org.skywalking
+ apm-resttemplate-plugin
+ ${project.version}
+
+
+ org.skywalking
+ apm-spring-concurrent-util-plugin
+ ${project.version}
+
diff --git a/apm-sniffer/apm-sdk-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/pom.xml
index 97bf4117a2a89a19539ad96f296f5f38dd2e5ac7..1b06f19d82cd2400a9d13cf33b4f2c5243a5eda7 100644
--- a/apm-sniffer/apm-sdk-plugin/pom.xml
+++ b/apm-sniffer/apm-sdk-plugin/pom.xml
@@ -22,6 +22,7 @@
okhttp-3.x-plugin
resin-3.x-plugin
resin-4.x-plugin
+ spring-plugins
pom
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2e3fd3b4f1463fabb0305b785c97cae41c274702
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/pom.xml
@@ -0,0 +1,24 @@
+
+
+ spring-plugins
+ org.skywalking
+ 3.2-2017
+
+ 4.0.0
+
+ apm-spring-concurrent-util-plugin
+ jar
+
+ concurrent-util-4.3.x-plugin
+ http://maven.apache.org
+
+
+
+ org.springframework
+ spring-core
+ 4.3.8.RELEASE
+ provided
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/FailureCallbackInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/FailureCallbackInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..56ae40584e817f4358c16bbdcfb471f2147783f7
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/FailureCallbackInterceptor.java
@@ -0,0 +1,44 @@
+package org.skywalking.apm.plugin.spring.concurrent;
+
+import java.net.URI;
+import org.skywalking.apm.agent.core.context.ContextManager;
+import org.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.skywalking.apm.agent.core.context.tag.Tags;
+import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.skywalking.apm.network.trace.component.ComponentsDefine;
+
+public class FailureCallbackInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
+ Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
+ if (cacheValues == null) {
+ return;
+ }
+
+ URI uri = (URI)cacheValues[0];
+ AbstractSpan span = ContextManager.createLocalSpan("future/failureCallback:" + uri.getPath());
+ span.errorOccurred().log((Throwable)allArguments[0]).setComponent(ComponentsDefine.REST_TEMPLATE).setLayer(SpanLayer.HTTP);
+ Tags.URL.set(span, uri.getPath());
+ ContextManager.continued((ContextSnapshot)cacheValues[2]);
+ }
+
+ @Override
+ public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
+ Class>[] argumentsTypes, Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override
+ public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/SuccessCallbackInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/SuccessCallbackInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..482a88638416b01c56fa97d9d399a0eeba24628b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/SuccessCallbackInterceptor.java
@@ -0,0 +1,41 @@
+package org.skywalking.apm.plugin.spring.concurrent;
+
+import java.net.URI;
+import org.skywalking.apm.agent.core.context.ContextManager;
+import org.skywalking.apm.agent.core.context.ContextSnapshot;
+import org.skywalking.apm.agent.core.context.tag.Tags;
+import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.skywalking.apm.agent.core.context.trace.SpanLayer;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+import org.skywalking.apm.network.trace.component.ComponentsDefine;
+
+public class SuccessCallbackInterceptor implements InstanceMethodsAroundInterceptor {
+
+ @Override public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
+ Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ Object[] cacheValues = (Object[])objInst.getSkyWalkingDynamicField();
+ if (cacheValues == null) {
+ return;
+ }
+
+ URI uri = (URI)cacheValues[0];
+ AbstractSpan span = ContextManager.createLocalSpan("future/successCallback:" + uri.getPath());
+ span.setComponent(ComponentsDefine.REST_TEMPLATE).setLayer(SpanLayer.HTTP);
+ Tags.URL.set(span, uri.getPath());
+ ContextManager.continued((ContextSnapshot)cacheValues[2]);
+ }
+
+ @Override public Object afterMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
+ Class>[] argumentsTypes, Object ret) throws Throwable {
+ ContextManager.stopSpan();
+ return ret;
+ }
+
+ @Override public void handleMethodException(EnhancedInstance objInst, String methodName, Object[] allArguments,
+ Class>[] argumentsTypes, Throwable t) {
+ ContextManager.activeSpan().errorOccurred().log(t);
+ }
+
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/FailureCallbackInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/FailureCallbackInstrumentation.java
new file mode 100644
index 0000000000000000000000000000000000000000..27d79b56639fbcdf54ce3eaec6e1d1dec0f17729
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/FailureCallbackInstrumentation.java
@@ -0,0 +1,56 @@
+package org.skywalking.apm.plugin.spring.concurrent.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.plugin.spring.concurrent.match.FailedCallbackMatch.failedCallbackMatch;
+
+/**
+ * {@link FailureCallbackInstrumentation} enhance the onFailure method that class inherited
+ * org.springframework.util.concurrent.FailureCallback
by {@link FailureCallbackInterceptor}.
+ *
+ * @author zhangxin
+ */
+public class FailureCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ public static final String FAILURE_CALLBACK_INTERCEPTOR = "org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor";
+ public static final String FAILURE_METHOD_NAME = "onFailure";
+
+ @Override
+ protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override
+ protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(FAILURE_METHOD_NAME);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return FAILURE_CALLBACK_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override
+ protected ClassMatch enhanceClass() {
+ return failedCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/ListenableFutureCallbackInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/ListenableFutureCallbackInstrumentation.java
new file mode 100644
index 0000000000000000000000000000000000000000..74ebbcad7c7e204f576855f0c08c931222389892
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/ListenableFutureCallbackInstrumentation.java
@@ -0,0 +1,65 @@
+package org.skywalking.apm.plugin.spring.concurrent.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor;
+import org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.plugin.spring.concurrent.match.ListenableFutureCallbackMatch.listenableFutureCallbackMatch;
+
+/**
+ * {@link ListenableFutureCallbackInstrumentation} enhance onSuccess
method and oonFailure
+ * that class inherited org.springframework.util.concurrent.ListenableFutureCallback
by {@link
+ * SuccessCallbackInterceptor} and {@link FailureCallbackInterceptor }.
+ *
+ * @author zhangxin
+ */
+public class ListenableFutureCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+ @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(SuccessCallbackInstrumentation.SUCCESS_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return SuccessCallbackInstrumentation.SUCCESS_CALLBACK_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ },
+ new InstanceMethodsInterceptPoint() {
+
+ @Override
+ public ElementMatcher getMethodsMatcher() {
+ return named(FailureCallbackInstrumentation.FAILURE_METHOD_NAME);
+ }
+
+ @Override
+ public String getMethodsInterceptor() {
+ return FailureCallbackInstrumentation.FAILURE_CALLBACK_INTERCEPTOR;
+ }
+
+ @Override
+ public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override protected ClassMatch enhanceClass() {
+ return listenableFutureCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/SuccessCallbackInstrumentation.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/SuccessCallbackInstrumentation.java
new file mode 100644
index 0000000000000000000000000000000000000000..4be5c33811e8a9c0c4d444b187dae420020cee52
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/define/SuccessCallbackInstrumentation.java
@@ -0,0 +1,51 @@
+package org.skywalking.apm.plugin.spring.concurrent.define;
+
+import net.bytebuddy.description.method.MethodDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
+import org.skywalking.apm.agent.core.plugin.interceptor.InstanceMethodsInterceptPoint;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassInstanceMethodsEnhancePluginDefine;
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.skywalking.apm.plugin.spring.concurrent.FailureCallbackInterceptor;
+import org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor;
+
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static org.skywalking.apm.plugin.spring.concurrent.match.SuccessCallbackMatch.successCallbackMatch;
+
+/**
+ * {@link SuccessCallbackInstrumentation} enhance the onSuccess
method that class inherited
+ * org.springframework.util.concurrent.SuccessCallback
by {@link SuccessCallbackInterceptor}.
+ *
+ * @author zhangxin
+ */
+public class SuccessCallbackInstrumentation extends ClassInstanceMethodsEnhancePluginDefine {
+
+ public static final String SUCCESS_CALLBACK_INTERCEPTOR = "org.skywalking.apm.plugin.spring.concurrent.SuccessCallbackInterceptor";
+ public static final String SUCCESS_METHOD_NAME = "onSuccess";
+
+ @Override protected ConstructorInterceptPoint[] getConstructorsInterceptPoints() {
+ return new ConstructorInterceptPoint[0];
+ }
+
+ @Override protected InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() {
+ return new InstanceMethodsInterceptPoint[] {
+ new InstanceMethodsInterceptPoint() {
+ @Override public ElementMatcher getMethodsMatcher() {
+ return named(SUCCESS_METHOD_NAME);
+ }
+
+ @Override public String getMethodsInterceptor() {
+ return SUCCESS_CALLBACK_INTERCEPTOR;
+ }
+
+ @Override public boolean isOverrideArgs() {
+ return false;
+ }
+ }
+ };
+ }
+
+ @Override protected ClassMatch enhanceClass() {
+ return successCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/EitherInterfaceMatch.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/EitherInterfaceMatch.java
new file mode 100644
index 0000000000000000000000000000000000000000..1396c6d2097b75608f8b0fdc17c33d49a9ba27cc
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/EitherInterfaceMatch.java
@@ -0,0 +1,77 @@
+package org.skywalking.apm.plugin.spring.concurrent.match;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
+import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
+
+/**
+ * {@link EitherInterfaceMatch} match the class inherited {@link #getMatchInterface() } and not inherited {@link
+ * #getMutexInterface()}
+ *
+ * @author zhangxin
+ */
+public abstract class EitherInterfaceMatch implements IndirectMatch {
+
+ private static final String SPRING_PACKAGE_PREFIX = "org.springframework";
+ private static final String OBJECT_CLASS_NAME = "java.lang.Object";
+
+ protected EitherInterfaceMatch() {
+
+ }
+
+ @Override
+ public ElementMatcher.Junction buildJunction() {
+ return not(nameStartsWith(SPRING_PACKAGE_PREFIX)).
+ and(hasSuperType(named(getMatchInterface())))
+ .and(not(hasSuperType(named(getMutexInterface()))));
+ }
+
+ @Override
+ public boolean isMatch(TypeDescription typeDescription) {
+ MatchResult matchResult = new MatchResult();
+ for (TypeDescription.Generic generic : typeDescription.getInterfaces()) {
+ matchHierarchyClazz(generic, matchResult);
+ }
+
+ matchHierarchyClazz(typeDescription.getSuperClass(), matchResult);
+ return matchResult.result();
+ }
+
+ public abstract String getMatchInterface();
+
+ public abstract String getMutexInterface();
+
+ private void matchHierarchyClazz(TypeDescription.Generic clazz, MatchResult matchResult) {
+ if (clazz.asRawType().getTypeName().equals(getMutexInterface())) {
+ matchResult.findMutexInterface = true;
+ return;
+ }
+
+ if (clazz.asRawType().getTypeName().equals(getMatchInterface())) {
+ matchResult.findMatchInterface = true;
+ }
+
+ for (TypeDescription.Generic generic : clazz.getInterfaces()) {
+ matchHierarchyClazz(generic, matchResult);
+ }
+
+ TypeDescription.Generic superClazz = clazz.getSuperClass();
+ if (superClazz != null && !clazz.getTypeName().equals(OBJECT_CLASS_NAME)) {
+ matchHierarchyClazz(superClazz, matchResult);
+ }
+ }
+
+ private static class MatchResult {
+ private boolean findMatchInterface = false;
+ private boolean findMutexInterface = false;
+
+ public boolean result() {
+ return findMatchInterface && !findMutexInterface;
+ }
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/FailedCallbackMatch.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/FailedCallbackMatch.java
new file mode 100644
index 0000000000000000000000000000000000000000..abcfde2497ade293dd4970d16c4dca09893a4007
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/FailedCallbackMatch.java
@@ -0,0 +1,31 @@
+package org.skywalking.apm.plugin.spring.concurrent.match;
+
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+/**
+ * {@link FailedCallbackMatch} match the class that inherited org.springframework.util.concurrent.FailureCallback
+ * and not inherited org.springframework.util.concurrent.SuccessCallback
+ *
+ * @author zhangxin
+ */
+public class FailedCallbackMatch extends EitherInterfaceMatch {
+
+ private static final String MATCH_INTERFACE = "org.springframework.util.concurrent.FailureCallback";
+ private static final String MUTEX_INTERFACE = "org.springframework.util.concurrent.SuccessCallback";
+
+ private FailedCallbackMatch() {
+
+ }
+
+ @Override public String getMatchInterface() {
+ return MATCH_INTERFACE;
+ }
+
+ @Override public String getMutexInterface() {
+ return MUTEX_INTERFACE;
+ }
+
+ public static ClassMatch failedCallbackMatch() {
+ return new FailedCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/ListenableFutureCallbackMatch.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/ListenableFutureCallbackMatch.java
new file mode 100644
index 0000000000000000000000000000000000000000..a18cf6f019cb08be42107c6546292bc151fa9e50
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/ListenableFutureCallbackMatch.java
@@ -0,0 +1,65 @@
+package org.skywalking.apm.plugin.spring.concurrent.match;
+
+import net.bytebuddy.description.type.TypeDescription;
+import net.bytebuddy.matcher.ElementMatcher;
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+import org.skywalking.apm.agent.core.plugin.match.IndirectMatch;
+
+import static net.bytebuddy.matcher.ElementMatchers.hasSuperType;
+import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith;
+import static net.bytebuddy.matcher.ElementMatchers.named;
+import static net.bytebuddy.matcher.ElementMatchers.not;
+
+/**
+ * {@link ListenableFutureCallbackMatch} match the class that inherited org.springframework.util.concurrent.ListenableFutureCallback
.
+ *
+ * @author zhangxin
+ */
+public class ListenableFutureCallbackMatch implements IndirectMatch {
+
+ private static final String LISTENABLE_FUTURE_CALLBACK_CLASS_NAME = "org.springframework.util.concurrent.ListenableFutureCallback";
+
+ private ListenableFutureCallbackMatch() {
+
+ }
+
+ @Override
+ public ElementMatcher.Junction buildJunction() {
+ return not(nameStartsWith("org.springframework")).
+ and(hasSuperType(named(LISTENABLE_FUTURE_CALLBACK_CLASS_NAME)));
+ }
+
+ @Override
+ public boolean isMatch(TypeDescription typeDescription) {
+ boolean isMatch = false;
+ for (TypeDescription.Generic generic : typeDescription.getInterfaces()) {
+ isMatch = isMatch || matchExactClass(generic);
+ }
+
+ return isMatch || matchExactClass(typeDescription.getSuperClass());
+ }
+
+ private boolean matchExactClass(TypeDescription.Generic clazz) {
+ if (clazz.asRawType().getTypeName().equals(LISTENABLE_FUTURE_CALLBACK_CLASS_NAME)) {
+ return true;
+ }
+
+ boolean isMatch = false;
+ for (TypeDescription.Generic generic : clazz.getInterfaces()) {
+ isMatch = isMatch || matchExactClass(generic);
+ }
+
+ if (!isMatch) {
+ TypeDescription.Generic superClazz = clazz.getSuperClass();
+ if (superClazz != null && !clazz.getTypeName().equals("java.lang.Object")) {
+ isMatch = isMatch || matchExactClass(superClazz);
+ }
+ }
+
+ return isMatch;
+ }
+
+ public static ClassMatch listenableFutureCallbackMatch() {
+ return new ListenableFutureCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/SuccessCallbackMatch.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/SuccessCallbackMatch.java
new file mode 100644
index 0000000000000000000000000000000000000000..309767198e639b59df25b2a04477adb02292566b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/concurrent/match/SuccessCallbackMatch.java
@@ -0,0 +1,32 @@
+package org.skywalking.apm.plugin.spring.concurrent.match;
+
+import org.skywalking.apm.agent.core.plugin.match.ClassMatch;
+
+/**
+ * {@link SuccessCallbackMatch} match the class that inherited org.springframework.util.concurrent.SuccessCallback
+ * and not inherited org.springframework.util.concurrent.FailureCallback
+ *
+ * @author zhangxin
+ */
+public class SuccessCallbackMatch extends EitherInterfaceMatch {
+
+ private static final String MATCH_INTERFACE = "org.springframework.util.concurrent.SuccessCallback";
+ private static final String MUTEX_INTERFACE = "org.springframework.util.concurrent.FailureCallback";
+
+ private SuccessCallbackMatch() {
+ }
+
+ @Override
+ public String getMatchInterface() {
+ return MATCH_INTERFACE;
+ }
+
+ @Override
+ public String getMutexInterface() {
+ return MUTEX_INTERFACE;
+ }
+
+ public static ClassMatch successCallbackMatch() {
+ return new SuccessCallbackMatch();
+ }
+}
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/resources/skywalking-plugin.def b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/resources/skywalking-plugin.def
new file mode 100644
index 0000000000000000000000000000000000000000..8c9426546886aa15c0ed91ccabf66147becd952b
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/concurrent-util-4.3.x-plugin/src/main/resources/skywalking-plugin.def
@@ -0,0 +1,3 @@
+spring-concurrent-util-4.3.8=org.skywalking.apm.plugin.spring.concurrent.define.FailureCallbackInstrumentation
+spring-concurrent-util-4.3.8=org.skywalking.apm.plugin.spring.concurrent.define.SuccessCallbackInstrumentation
+spring-concurrent-util-4.3.8=org.skywalking.apm.plugin.spring.concurrent.define.ListenableFutureCallbackInstrumentation
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a7558877d00abddaba55b1fcbd9596d2e4c9c6cf
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/pom.xml
@@ -0,0 +1,26 @@
+
+
+ 4.0.0
+
+
+ org.skywalking
+ apm-sdk-plugin
+ 3.2-2017
+
+
+ spring-plugins
+
+ concurrent-util-4.3.x-plugin
+ resttemplate-4.3.x-plugin
+
+ pom
+
+ apm-sdk-plugin
+ http://maven.apache.org
+
+
+ UTF-8
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/pom.xml b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3dde8eb50b6d09362f9b369ebc2db3315198d474
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/pom.xml
@@ -0,0 +1,24 @@
+
+
+ spring-plugins
+ org.skywalking
+ 3.2-2017
+
+ 4.0.0
+
+ apm-resttemplate-plugin
+ jar
+
+ resttemplate-4.3.x-plugin
+ http://maven.apache.org
+
+
+
+ org.springframework
+ spring-web
+ 4.3.8.RELEASE
+ provided
+
+
+
diff --git a/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/FutureGetInterceptor.java b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/FutureGetInterceptor.java
new file mode 100644
index 0000000000000000000000000000000000000000..102ba4e3bac38db54d3cf90df6ff150bbb2631a5
--- /dev/null
+++ b/apm-sniffer/apm-sdk-plugin/spring-plugins/resttemplate-4.3.x-plugin/src/main/java/org/skywalking/apm/plugin/spring/resttemplate/async/FutureGetInterceptor.java
@@ -0,0 +1,33 @@
+package org.skywalking.apm.plugin.spring.resttemplate.async;
+
+import com.google.instrumentation.trace.Span;
+import java.net.URI;
+import java.util.List;
+import org.skywalking.apm.agent.core.context.ContextManager;
+import org.skywalking.apm.agent.core.context.trace.AbstractSpan;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.InstanceMethodsAroundInterceptor;
+import org.skywalking.apm.agent.core.plugin.interceptor.enhance.MethodInterceptResult;
+
+public class FutureGetInterceptor implements InstanceMethodsAroundInterceptor {
+ @Override
+ public void beforeMethod(EnhancedInstance objInst, String methodName, Object[] allArguments,
+ Class>[] argumentsTypes, MethodInterceptResult result) throws Throwable {
+ List