diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java
index 87bfae3ed..131ddfb86 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/AbstractClassEnhancePluginDefine.java
@@ -26,7 +26,7 @@ public abstract class AbstractClassEnhancePluginDefine {
* @throws PluginException, when set builder failure.
*/
public DynamicType.Builder> define(String transformClassName,
- DynamicType.Builder> builder, ClassLoader classLoader) throws PluginException {
+ DynamicType.Builder> builder, ClassLoader classLoader, EnhanceContext context) throws PluginException {
String interceptorDefineClassName = this.getClass().getName();
if (StringUtil.isEmpty(transformClassName)) {
@@ -53,15 +53,16 @@ public abstract class AbstractClassEnhancePluginDefine {
/**
* find origin class source code for interceptor
*/
- DynamicType.Builder> newClassBuilder = this.enhance(transformClassName, builder, classLoader);
+ DynamicType.Builder> newClassBuilder = this.enhance(transformClassName, builder, classLoader, context);
+ context.initializationStageCompleted();
logger.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);
return newClassBuilder;
}
protected abstract DynamicType.Builder> enhance(String enhanceOriginClassName,
- DynamicType.Builder> newClassBuilder, ClassLoader classLoader) throws PluginException;
+ DynamicType.Builder> newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException;
/**
* Define the {@link ClassMatch} for filtering class.
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/EnhanceContext.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/EnhanceContext.java
new file mode 100644
index 000000000..e3417c38d
--- /dev/null
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/EnhanceContext.java
@@ -0,0 +1,34 @@
+package org.skywalking.apm.agent.core.plugin;
+
+/**
+ * The EnhanceContext represents the context or status for processing a class.
+ *
+ * Based on this context, the plugin core {@link org.skywalking.apm.agent.core.plugin.interceptor.enhance.ClassEnhancePluginDefine}
+ * knows how to process the specific steps for every particular plugin.
+ *
+ * @author wusheng
+ */
+public class EnhanceContext {
+ private boolean isEnhanced = false;
+ /**
+ * The object has already been enhanced or extended.
+ * e.g. added the new field, or implemented the new interface
+ */
+ private boolean objectExtended = false;
+
+ public boolean isEnhanced() {
+ return isEnhanced;
+ }
+
+ public void initializationStageCompleted() {
+ isEnhanced = true;
+ }
+
+ public boolean isObjectExtended() {
+ return objectExtended;
+ }
+
+ public void extendObjectCompleted() {
+ objectExtended = true;
+ }
+}
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/PluginFinder.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/PluginFinder.java
index 271b32cee..96e90fee6 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/PluginFinder.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/PluginFinder.java
@@ -22,7 +22,7 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
* @author wusheng
*/
public class PluginFinder {
- private final Map nameMatchDefine = new HashMap();
+ private final Map> nameMatchDefine = new HashMap>();
private final List signatureMatchDefine = new LinkedList();
public PluginFinder(List plugins) {
@@ -35,28 +35,34 @@ public class PluginFinder {
if (match instanceof NameMatch) {
NameMatch nameMatch = (NameMatch)match;
- nameMatchDefine.put(nameMatch.getClassName(), plugin);
+ LinkedList pluginDefines = nameMatchDefine.get(nameMatch.getClassName());
+ if (pluginDefines == null) {
+ pluginDefines = new LinkedList();
+ nameMatchDefine.put(nameMatch.getClassName(), pluginDefines);
+ }
+ pluginDefines.add(plugin);
} else {
signatureMatchDefine.add(plugin);
}
}
}
- public AbstractClassEnhancePluginDefine find(TypeDescription typeDescription,
+ public List find(TypeDescription typeDescription,
ClassLoader classLoader) {
+ List matchedPlugins = new LinkedList();
String typeName = typeDescription.getTypeName();
if (nameMatchDefine.containsKey(typeName)) {
- return nameMatchDefine.get(typeName);
+ matchedPlugins.addAll(nameMatchDefine.get(typeName));
}
for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {
IndirectMatch match = (IndirectMatch)pluginDefine.enhanceClass();
if (match.isMatch(typeDescription)) {
- return pluginDefine;
+ matchedPlugins.add(pluginDefine);
}
}
- return null;
+ return matchedPlugins;
}
public ElementMatcher super TypeDescription> buildMatch() {
diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java
index 3dc7075cb..b31e2c3b2 100644
--- a/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java
+++ b/apm-sniffer/apm-agent-core/src/main/java/org/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java
@@ -6,6 +6,7 @@ import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.implementation.bind.annotation.Morph;
import org.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
+import org.skywalking.apm.agent.core.plugin.EnhanceContext;
import org.skywalking.apm.agent.core.plugin.PluginException;
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.skywalking.apm.agent.core.plugin.interceptor.EnhanceException;
@@ -46,10 +47,11 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
*/
@Override
protected DynamicType.Builder> enhance(String enhanceOriginClassName,
- DynamicType.Builder> newClassBuilder, ClassLoader classLoader) throws PluginException {
+ DynamicType.Builder> newClassBuilder, ClassLoader classLoader,
+ EnhanceContext context) throws PluginException {
newClassBuilder = this.enhanceClass(enhanceOriginClassName, newClassBuilder, classLoader);
- newClassBuilder = this.enhanceInstance(enhanceOriginClassName, newClassBuilder, classLoader);
+ newClassBuilder = this.enhanceInstance(enhanceOriginClassName, newClassBuilder, classLoader, context);
return newClassBuilder;
}
@@ -62,7 +64,8 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
* @return new byte-buddy's builder for further manipulation.
*/
private DynamicType.Builder> enhanceInstance(String enhanceOriginClassName,
- DynamicType.Builder> newClassBuilder, ClassLoader classLoader) throws PluginException {
+ DynamicType.Builder> newClassBuilder, ClassLoader classLoader,
+ EnhanceContext context) throws PluginException {
ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints();
InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints();
@@ -83,16 +86,21 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
}
/**
- * alter class source code.
+ * Manipulate class source code.
*
* new class need:
* 1.Add field, name {@link #CONTEXT_ATTR_NAME}.
* 2.Add a field accessor for this field.
*
+ * And make sure the source codes manipulation only occurs once.
+ *
*/
- newClassBuilder = newClassBuilder.defineField(CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE)
- .implement(EnhancedInstance.class)
- .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
+ if (!context.isObjectExtended()) {
+ newClassBuilder = newClassBuilder.defineField(CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE)
+ .implement(EnhancedInstance.class)
+ .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
+ context.extendObjectCompleted();
+ }
/**
* 2. enhance constructors
diff --git a/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/SkyWalkingAgent.java b/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/SkyWalkingAgent.java
index 1edf9f841..fde12af83 100644
--- a/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/SkyWalkingAgent.java
+++ b/apm-sniffer/apm-agent/src/main/java/org/skywalking/apm/agent/SkyWalkingAgent.java
@@ -1,6 +1,7 @@
package org.skywalking.apm.agent;
import java.lang.instrument.Instrumentation;
+import java.util.List;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType;
@@ -9,6 +10,7 @@ import org.skywalking.apm.agent.core.boot.ServiceManager;
import org.skywalking.apm.agent.core.conf.SnifferConfigInitializer;
import org.skywalking.apm.agent.core.logging.EasyLogResolver;
import org.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine;
+import org.skywalking.apm.agent.core.plugin.EnhanceContext;
import org.skywalking.apm.agent.core.plugin.PluginBootstrap;
import org.skywalking.apm.agent.core.plugin.PluginException;
import org.skywalking.apm.agent.core.plugin.PluginFinder;
@@ -54,13 +56,21 @@ public class SkyWalkingAgent {
@Override
public DynamicType.Builder> transform(DynamicType.Builder> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) {
- AbstractClassEnhancePluginDefine pluginDefine = pluginFinder.find(typeDescription, classLoader);
- if (pluginDefine != null) {
- DynamicType.Builder> newBuilder = pluginDefine.define(typeDescription.getTypeName(), builder, classLoader);
- if (newBuilder != null) {
- logger.debug("Finish the prepare stage for {}.", typeDescription.getName());
- return newBuilder;
+ List pluginDefines = pluginFinder.find(typeDescription, classLoader);
+ if (pluginDefines.size() > 0) {
+ DynamicType.Builder> newBuilder = builder;
+ EnhanceContext context = new EnhanceContext();
+ for (AbstractClassEnhancePluginDefine define : pluginDefines) {
+ DynamicType.Builder> possibleNewBuilder = define.define(typeDescription.getTypeName(), builder, classLoader, context);
+ if (possibleNewBuilder != null) {
+ newBuilder = possibleNewBuilder;
+ }
}
+ if (context.isEnhanced()) {
+ logger.debug("Finish the prepare stage for {}.", typeDescription.getName());
+ }
+
+ return newBuilder;
}
logger.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName());