提交 2647a906 编写于 作者: wu-sheng's avatar wu-sheng 提交者: IluckySi

Support multi plugin defines targeting the same class. Relate to #402, but...

Support multi plugin defines targeting the same class. Relate to #402, but more than that. e.g. Enhance a class in the certain version library, but we need multi plugins to do so, like @clevertension ’s #465
上级 1a36dc80
...@@ -26,7 +26,7 @@ public abstract class AbstractClassEnhancePluginDefine { ...@@ -26,7 +26,7 @@ public abstract class AbstractClassEnhancePluginDefine {
* @throws PluginException, when set builder failure. * @throws PluginException, when set builder failure.
*/ */
public DynamicType.Builder<?> define(String transformClassName, 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(); String interceptorDefineClassName = this.getClass().getName();
if (StringUtil.isEmpty(transformClassName)) { if (StringUtil.isEmpty(transformClassName)) {
...@@ -53,15 +53,16 @@ public abstract class AbstractClassEnhancePluginDefine { ...@@ -53,15 +53,16 @@ public abstract class AbstractClassEnhancePluginDefine {
/** /**
* find origin class source code for interceptor * 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); logger.debug("enhance class {} by {} completely.", transformClassName, interceptorDefineClassName);
return newClassBuilder; return newClassBuilder;
} }
protected abstract DynamicType.Builder<?> enhance(String enhanceOriginClassName, 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. * Define the {@link ClassMatch} for filtering class.
......
package org.skywalking.apm.agent.core.plugin;
/**
* The <code>EnhanceContext</code> 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;
}
}
...@@ -22,7 +22,7 @@ import static net.bytebuddy.matcher.ElementMatchers.not; ...@@ -22,7 +22,7 @@ import static net.bytebuddy.matcher.ElementMatchers.not;
* @author wusheng * @author wusheng
*/ */
public class PluginFinder { public class PluginFinder {
private final Map<String, AbstractClassEnhancePluginDefine> nameMatchDefine = new HashMap<String, AbstractClassEnhancePluginDefine>(); private final Map<String, LinkedList<AbstractClassEnhancePluginDefine>> nameMatchDefine = new HashMap<String, LinkedList<AbstractClassEnhancePluginDefine>>();
private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new LinkedList<AbstractClassEnhancePluginDefine>(); private final List<AbstractClassEnhancePluginDefine> signatureMatchDefine = new LinkedList<AbstractClassEnhancePluginDefine>();
public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) { public PluginFinder(List<AbstractClassEnhancePluginDefine> plugins) {
...@@ -35,28 +35,34 @@ public class PluginFinder { ...@@ -35,28 +35,34 @@ public class PluginFinder {
if (match instanceof NameMatch) { if (match instanceof NameMatch) {
NameMatch nameMatch = (NameMatch)match; NameMatch nameMatch = (NameMatch)match;
nameMatchDefine.put(nameMatch.getClassName(), plugin); LinkedList<AbstractClassEnhancePluginDefine> pluginDefines = nameMatchDefine.get(nameMatch.getClassName());
if (pluginDefines == null) {
pluginDefines = new LinkedList<AbstractClassEnhancePluginDefine>();
nameMatchDefine.put(nameMatch.getClassName(), pluginDefines);
}
pluginDefines.add(plugin);
} else { } else {
signatureMatchDefine.add(plugin); signatureMatchDefine.add(plugin);
} }
} }
} }
public AbstractClassEnhancePluginDefine find(TypeDescription typeDescription, public List<AbstractClassEnhancePluginDefine> find(TypeDescription typeDescription,
ClassLoader classLoader) { ClassLoader classLoader) {
List<AbstractClassEnhancePluginDefine> matchedPlugins = new LinkedList<AbstractClassEnhancePluginDefine>();
String typeName = typeDescription.getTypeName(); String typeName = typeDescription.getTypeName();
if (nameMatchDefine.containsKey(typeName)) { if (nameMatchDefine.containsKey(typeName)) {
return nameMatchDefine.get(typeName); matchedPlugins.addAll(nameMatchDefine.get(typeName));
} }
for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) { for (AbstractClassEnhancePluginDefine pluginDefine : signatureMatchDefine) {
IndirectMatch match = (IndirectMatch)pluginDefine.enhanceClass(); IndirectMatch match = (IndirectMatch)pluginDefine.enhanceClass();
if (match.isMatch(typeDescription)) { if (match.isMatch(typeDescription)) {
return pluginDefine; matchedPlugins.add(pluginDefine);
} }
} }
return null; return matchedPlugins;
} }
public ElementMatcher<? super TypeDescription> buildMatch() { public ElementMatcher<? super TypeDescription> buildMatch() {
......
...@@ -6,6 +6,7 @@ import net.bytebuddy.implementation.MethodDelegation; ...@@ -6,6 +6,7 @@ import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.SuperMethodCall; import net.bytebuddy.implementation.SuperMethodCall;
import net.bytebuddy.implementation.bind.annotation.Morph; import net.bytebuddy.implementation.bind.annotation.Morph;
import org.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine; 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.PluginException;
import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint; import org.skywalking.apm.agent.core.plugin.interceptor.ConstructorInterceptPoint;
import org.skywalking.apm.agent.core.plugin.interceptor.EnhanceException; import org.skywalking.apm.agent.core.plugin.interceptor.EnhanceException;
...@@ -46,10 +47,11 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi ...@@ -46,10 +47,11 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
*/ */
@Override @Override
protected DynamicType.Builder<?> enhance(String enhanceOriginClassName, 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.enhanceClass(enhanceOriginClassName, newClassBuilder, classLoader);
newClassBuilder = this.enhanceInstance(enhanceOriginClassName, newClassBuilder, classLoader); newClassBuilder = this.enhanceInstance(enhanceOriginClassName, newClassBuilder, classLoader, context);
return newClassBuilder; return newClassBuilder;
} }
...@@ -62,7 +64,8 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi ...@@ -62,7 +64,8 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
* @return new byte-buddy's builder for further manipulation. * @return new byte-buddy's builder for further manipulation.
*/ */
private DynamicType.Builder<?> enhanceInstance(String enhanceOriginClassName, 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(); ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints();
InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints(); InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints();
...@@ -83,16 +86,21 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi ...@@ -83,16 +86,21 @@ public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePlugi
} }
/** /**
* alter class source code.<br/> * Manipulate class source code.<br/>
* *
* new class need:<br/> * new class need:<br/>
* 1.Add field, name {@link #CONTEXT_ATTR_NAME}. * 1.Add field, name {@link #CONTEXT_ATTR_NAME}.
* 2.Add a field accessor for this field. * 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) if (!context.isObjectExtended()) {
.implement(EnhancedInstance.class) newClassBuilder = newClassBuilder.defineField(CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE)
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME)); .implement(EnhancedInstance.class)
.intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME));
context.extendObjectCompleted();
}
/** /**
* 2. enhance constructors * 2. enhance constructors
......
package org.skywalking.apm.agent; package org.skywalking.apm.agent;
import java.lang.instrument.Instrumentation; import java.lang.instrument.Instrumentation;
import java.util.List;
import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeDescription;
import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.DynamicType;
...@@ -9,6 +10,7 @@ import org.skywalking.apm.agent.core.boot.ServiceManager; ...@@ -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.conf.SnifferConfigInitializer;
import org.skywalking.apm.agent.core.logging.EasyLogResolver; import org.skywalking.apm.agent.core.logging.EasyLogResolver;
import org.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine; 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.PluginBootstrap;
import org.skywalking.apm.agent.core.plugin.PluginException; import org.skywalking.apm.agent.core.plugin.PluginException;
import org.skywalking.apm.agent.core.plugin.PluginFinder; import org.skywalking.apm.agent.core.plugin.PluginFinder;
...@@ -54,13 +56,21 @@ public class SkyWalkingAgent { ...@@ -54,13 +56,21 @@ public class SkyWalkingAgent {
@Override @Override
public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription, public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
ClassLoader classLoader, JavaModule module) { ClassLoader classLoader, JavaModule module) {
AbstractClassEnhancePluginDefine pluginDefine = pluginFinder.find(typeDescription, classLoader); List<AbstractClassEnhancePluginDefine> pluginDefines = pluginFinder.find(typeDescription, classLoader);
if (pluginDefine != null) { if (pluginDefines.size() > 0) {
DynamicType.Builder<?> newBuilder = pluginDefine.define(typeDescription.getTypeName(), builder, classLoader); DynamicType.Builder<?> newBuilder = builder;
if (newBuilder != null) { 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()); logger.debug("Finish the prepare stage for {}.", typeDescription.getName());
return newBuilder;
} }
return newBuilder;
} }
logger.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName()); logger.debug("Matched class {}, but ignore by finding mechanism.", typeDescription.getTypeName());
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册