diff --git a/CHANGES.md b/CHANGES.md index a63f4a9a5..3129731e8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,7 +19,7 @@ Release Notes. * Upgrade netty-codec-http2 to 4.1.100.Final * Add a netty-http 4.1.x plugin to trace HTTP requests. * Fix Impala Jdbc URL (including schema without properties) parsing exception. - +* Optimize byte-buddy type description performance. #### Documentation diff --git a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Constants.java b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Constants.java index ae6095a06..2f6fed7b3 100644 --- a/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Constants.java +++ b/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/conf/Constants.java @@ -36,6 +36,6 @@ public class Constants { /** * The name trait for auxiliary type names, field names and method names which generated by ByteBuddy. */ - public static final String NAME_TRAIT = "sw$"; + public static final String NAME_TRAIT = "$sw$"; } diff --git a/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java b/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java index 8e0c2495b..19a0bb891 100644 --- a/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java +++ b/apm-sniffer/apm-agent/src/main/java/org/apache/skywalking/apm/agent/SkyWalkingAgent.java @@ -23,9 +23,11 @@ import java.security.ProtectionDomain; import java.util.Collections; import java.util.List; import java.util.Map; + import net.bytebuddy.ByteBuddy; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.agent.builder.SWAgentBuilderDefault; +import net.bytebuddy.agent.builder.SWDescriptionStrategy; import net.bytebuddy.agent.builder.SWNativeMethodStrategy; import net.bytebuddy.description.NamedElement; import net.bytebuddy.description.type.TypeDescription; @@ -156,9 +158,8 @@ public class SkyWalkingAgent { .with(new SWAuxiliaryTypeNamingStrategy(NAME_TRAIT)) .with(new SWImplementationContextFactory(NAME_TRAIT)); - SWNativeMethodStrategy nativeMethodStrategy = new SWNativeMethodStrategy(NAME_TRAIT); - return new SWAgentBuilderDefault(byteBuddy, nativeMethodStrategy) - .with(AgentBuilder.DescriptionStrategy.Default.POOL_FIRST); + return new SWAgentBuilderDefault(byteBuddy, new SWNativeMethodStrategy(NAME_TRAIT)) + .with(new SWDescriptionStrategy(NAME_TRAIT)); } private static class Transformer implements AgentBuilder.Transformer { diff --git a/apm-sniffer/bytebuddy-patch/src/main/java/net/bytebuddy/agent/builder/SWDescriptionStrategy.java b/apm-sniffer/bytebuddy-patch/src/main/java/net/bytebuddy/agent/builder/SWDescriptionStrategy.java new file mode 100644 index 000000000..8f4b66ef0 --- /dev/null +++ b/apm-sniffer/bytebuddy-patch/src/main/java/net/bytebuddy/agent/builder/SWDescriptionStrategy.java @@ -0,0 +1,335 @@ +/* + * 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 net.bytebuddy.agent.builder; + +import net.bytebuddy.description.annotation.AnnotationList; +import net.bytebuddy.description.field.FieldDescription; +import net.bytebuddy.description.field.FieldList; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.method.MethodList; +import net.bytebuddy.description.type.*; +import net.bytebuddy.dynamic.TargetType; +import net.bytebuddy.implementation.bytecode.StackSize; +import net.bytebuddy.pool.TypePool; +import net.bytebuddy.utility.JavaModule; +import net.bytebuddy.utility.nullability.MaybeNull; +import org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; + +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * A DescriptionStrategy to get the original class description by removing dynamic field and method tokens + * generated by SkyWalking. + */ +public class SWDescriptionStrategy implements AgentBuilder.DescriptionStrategy { + + /** + * A cache of type descriptions for commonly used types to avoid unnecessary allocations. + */ + private static final Map, TypeDescription> TYPE_CACHE; + + /* + * Initializes the type cache. + */ + static { + TYPE_CACHE = new HashMap, TypeDescription>(); + TYPE_CACHE.put(TargetType.class, new TypeDescription.ForLoadedType(TargetType.class)); + TYPE_CACHE.put(Class.class, new TypeDescription.ForLoadedType(Class.class)); + TYPE_CACHE.put(Throwable.class, new TypeDescription.ForLoadedType(Throwable.class)); + TYPE_CACHE.put(Annotation.class, new TypeDescription.ForLoadedType(Annotation.class)); + TYPE_CACHE.put(Object.class, new TypeDescription.ForLoadedType(Object.class)); + TYPE_CACHE.put(String.class, new TypeDescription.ForLoadedType(String.class)); + TYPE_CACHE.put(Boolean.class, new TypeDescription.ForLoadedType(Boolean.class)); + TYPE_CACHE.put(Byte.class, new TypeDescription.ForLoadedType(Byte.class)); + TYPE_CACHE.put(Short.class, new TypeDescription.ForLoadedType(Short.class)); + TYPE_CACHE.put(Character.class, new TypeDescription.ForLoadedType(Character.class)); + TYPE_CACHE.put(Integer.class, new TypeDescription.ForLoadedType(Integer.class)); + TYPE_CACHE.put(Long.class, new TypeDescription.ForLoadedType(Long.class)); + TYPE_CACHE.put(Float.class, new TypeDescription.ForLoadedType(Float.class)); + TYPE_CACHE.put(Double.class, new TypeDescription.ForLoadedType(Double.class)); + TYPE_CACHE.put(void.class, new TypeDescription.ForLoadedType(void.class)); + TYPE_CACHE.put(boolean.class, new TypeDescription.ForLoadedType(boolean.class)); + TYPE_CACHE.put(byte.class, new TypeDescription.ForLoadedType(byte.class)); + TYPE_CACHE.put(short.class, new TypeDescription.ForLoadedType(short.class)); + TYPE_CACHE.put(char.class, new TypeDescription.ForLoadedType(char.class)); + TYPE_CACHE.put(int.class, new TypeDescription.ForLoadedType(int.class)); + TYPE_CACHE.put(long.class, new TypeDescription.ForLoadedType(long.class)); + TYPE_CACHE.put(float.class, new TypeDescription.ForLoadedType(float.class)); + TYPE_CACHE.put(double.class, new TypeDescription.ForLoadedType(double.class)); + } + + private AgentBuilder.DescriptionStrategy delegate = Default.HYBRID; + + private String nameTrait; + + public SWDescriptionStrategy(String nameTrait) { + this.nameTrait = nameTrait; + } + + @Override + public boolean isLoadedFirst() { + return true; + } + + @Override + public TypeDescription apply(String name, + @MaybeNull Class type, + TypePool typePool, + AgentBuilder.CircularityLock circularityLock, + @MaybeNull ClassLoader classLoader, + @MaybeNull JavaModule module) { + // find from type cache + if (type != null) { + TypeDescription typeDescription = TYPE_CACHE.get(type); + if (typeDescription != null) { + return typeDescription; + } + } + // wrap result + return new SWTypeDescriptionWrapper(delegate.apply(name, type, typePool, circularityLock, classLoader, module), nameTrait); + } + + /** + * A TypeDescription wrapper to remove fields, methods, interface generated by SkyWalking. + */ + static class SWTypeDescriptionWrapper extends TypeDescription.AbstractBase implements Serializable { + + /** + * The class's serial version UID. + */ + private static final long serialVersionUID = 1L; + + private static final List IGNORED_INTERFACES = Arrays.asList(EnhancedInstance.class.getName()); + + private static final List IGNORED_FIELDS = Arrays.asList(AbstractClassEnhancePluginDefine.CONTEXT_ATTR_NAME); + + private static final List IGNORED_METHODS = Arrays.asList("getSkyWalkingDynamicField", "setSkyWalkingDynamicField"); + + private MethodList methods; + + private FieldList fields; + + private final String nameTrait; + + private TypeList.Generic interfaces; + + private TypeDescription delegate; + + public SWTypeDescriptionWrapper(TypeDescription delegate, String nameTrait) { + this.delegate = delegate; + this.nameTrait = nameTrait; + } + + @Override + public TypeList.Generic getInterfaces() { + if (this.interfaces == null) { + TypeList.Generic allInterfaces = delegate.getInterfaces(); + if (allInterfaces.stream().anyMatch(s -> IGNORED_INTERFACES.contains(s.getTypeName()))) { + // remove interfaces added by SkyWalking + List list = allInterfaces.stream() + .filter(s -> !IGNORED_INTERFACES.contains(s.getTypeName())) + .collect(Collectors.toList()); + this.interfaces = new TypeList.Generic.Explicit(list); + } else { + this.interfaces = allInterfaces; + } + } + return this.interfaces; + } + + @Override + public FieldList getDeclaredFields() { + if (this.fields == null) { + FieldList declaredFields = delegate.getDeclaredFields(); + if (declaredFields.stream() + .anyMatch(f -> f.getName().contains(nameTrait) || IGNORED_FIELDS.contains(f.getName()))) { + // Remove dynamic field tokens generated by SkyWalking + fields = new FieldList.Explicit<>(declaredFields.stream() + .filter(f -> !f.getName().contains(nameTrait) && !IGNORED_FIELDS.contains(f.getName())) + .collect(Collectors.toList())); + } else { + fields = declaredFields; + } + } + return fields; + } + + @Override + public MethodList getDeclaredMethods() { + if (this.methods == null) { + MethodList declaredMethods = delegate.getDeclaredMethods(); + if (declaredMethods.stream() + .anyMatch(m -> m.getName().contains(nameTrait) || IGNORED_METHODS.contains(m.getName()))) { + // Remove dynamic method tokens generated by SkyWalking + methods = new MethodList.Explicit<>(declaredMethods.stream() + .filter(m -> !m.getName().contains(nameTrait) && !IGNORED_METHODS.contains(m.getName())) + .collect(Collectors.toList())); + } else { + methods = declaredMethods; + } + } + return methods; + } + + @Override + public boolean isAssignableTo(Class type) { + // ignore interface added by SkyWalking + if (IGNORED_INTERFACES.contains(type.getName())) { + return false; + } + return delegate.isAssignableTo(type); + } + + @Override + public boolean isAccessibleTo(TypeDescription typeDescription) { + // ignore interface added by SkyWalking + if (IGNORED_INTERFACES.contains(typeDescription.getName())) { + return false; + } + return delegate.isAccessibleTo(typeDescription); + } + + @Override + public RecordComponentList getRecordComponents() { + return delegate.getRecordComponents(); + } + + @Override + public TypeDescription getComponentType() { + return delegate.getComponentType(); + } + + @Override + public TypeDescription getDeclaringType() { + return delegate.getDeclaringType(); + } + + @Override + public TypeList getDeclaredTypes() { + return delegate.getDeclaredTypes(); + } + + @Override + public MethodDescription.InDefinedShape getEnclosingMethod() { + return delegate.getEnclosingMethod(); + } + + @Override + public TypeDescription getEnclosingType() { + return delegate.getEnclosingType(); + } + + @Override + public String getSimpleName() { + return delegate.getSimpleName(); + } + + @Override + public String getCanonicalName() { + return delegate.getCanonicalName(); + } + + @Override + public boolean isAnonymousType() { + return delegate.isAnonymousType(); + } + + @Override + public boolean isLocalType() { + return delegate.isLocalType(); + } + + @Override + public PackageDescription getPackage() { + return delegate.getPackage(); + } + + @Override + public TypeDescription getNestHost() { + return delegate.getNestHost(); + } + + @Override + public TypeList getNestMembers() { + return delegate.getNestMembers(); + } + + @Override + public TypeList getPermittedSubtypes() { + return delegate.getPermittedSubtypes(); + } + + @Override + public String getDescriptor() { + return delegate.getDescriptor(); + } + + @Override + public String getName() { + return delegate.getName(); + } + + @Override + public TypeList.Generic getTypeVariables() { + return delegate.getTypeVariables(); + } + + @Override + public AnnotationList getDeclaredAnnotations() { + return delegate.getDeclaredAnnotations(); + } + + @Override + public Generic getSuperClass() { + return delegate.getSuperClass(); + } + + @Override + public StackSize getStackSize() { + return delegate.getStackSize(); + } + + @Override + public boolean isArray() { + return delegate.isArray(); + } + + @Override + public boolean isRecord() { + return delegate.isRecord(); + } + + @Override + public boolean isPrimitive() { + return delegate.isPrimitive(); + } + + @Override + public int getModifiers() { + return delegate.getModifiers(); + } + } +} diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/SWClassFileLocator.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/SWClassFileLocator.java index 564e4471a..6d9f290db 100644 --- a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/SWClassFileLocator.java +++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/SWClassFileLocator.java @@ -35,7 +35,7 @@ import java.util.concurrent.TimeUnit; */ public class SWClassFileLocator implements ClassFileLocator { private static final ILog LOGGER = LogManager.getLogger(SWClassFileLocator.class); - private static final String[] TYPE_NAME_TRAITS = {"auxiliary$", "ByteBuddy$", "sw$"}; + private static final String[] TYPE_NAME_TRAITS = {"auxiliary$", "ByteBuddy$", "$sw$"}; private static final int DEFAULT_TIMEOUT_SECONDS = 2; private final ForInstrumentation.ClassLoadingDelegate classLoadingDelegate; diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/BizFoo.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/BizFoo.java index 95aaaca1e..444b66eb0 100644 --- a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/BizFoo.java +++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/BizFoo.java @@ -18,7 +18,7 @@ package org.apache.skywalking.apm.agent.bytebuddy.biz; -public class BizFoo { +public class BizFoo implements BizInterface { private String name; diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/BizInterface.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/BizInterface.java new file mode 100644 index 000000000..9a5a04174 --- /dev/null +++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/biz/BizInterface.java @@ -0,0 +1,23 @@ +/* + * 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.agent.bytebuddy.biz; + +public interface BizInterface { + +} diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java index c89985ce1..ba9cf4d37 100644 --- a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java +++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/AbstractInterceptTest.java @@ -22,7 +22,9 @@ import net.bytebuddy.ByteBuddy; import net.bytebuddy.agent.ByteBuddyAgent; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.agent.builder.SWAgentBuilderDefault; +import net.bytebuddy.agent.builder.SWDescriptionStrategy; import net.bytebuddy.agent.builder.SWNativeMethodStrategy; +import net.bytebuddy.implementation.FieldAccessor; import net.bytebuddy.implementation.MethodDelegation; import net.bytebuddy.implementation.SWImplementationContextFactory; import net.bytebuddy.implementation.SuperMethodCall; @@ -36,6 +38,7 @@ import org.apache.skywalking.apm.agent.bytebuddy.SWAsmVisitorWrapper; import org.apache.skywalking.apm.agent.bytebuddy.SWAuxiliaryTypeNamingStrategy; import org.apache.skywalking.apm.agent.bytebuddy.SWClassFileLocator; import org.apache.skywalking.apm.agent.bytebuddy.biz.BizFoo; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Rule; @@ -52,6 +55,10 @@ import java.security.ProtectionDomain; import java.util.Arrays; import java.util.List; +import static net.bytebuddy.jar.asm.Opcodes.ACC_PRIVATE; +import static net.bytebuddy.jar.asm.Opcodes.ACC_VOLATILE; +import static org.apache.skywalking.apm.agent.core.plugin.AbstractClassEnhancePluginDefine.CONTEXT_ATTR_NAME; + public class AbstractInterceptTest { public static final String BIZ_FOO_CLASS_NAME = "org.apache.skywalking.apm.agent.bytebuddy.biz.BizFoo"; public static final String PROJECT_SERVICE_CLASS_NAME = "org.apache.skywalking.apm.agent.bytebuddy.biz.ProjectService"; @@ -60,7 +67,7 @@ public class AbstractInterceptTest { public static final int BASE_INT_VALUE = 100; public static final String CONSTRUCTOR_INTERCEPTOR_CLASS = "constructorInterceptorClass"; public static final String METHOD_INTERCEPTOR_CLASS = "methodInterceptorClass"; - protected List nameTraits = Arrays.asList("sw2023", "sw2024"); + protected List nameTraits = Arrays.asList("$sw$", "$sw$2"); protected boolean deleteDuplicatedFields = false; @BeforeClass @@ -106,6 +113,11 @@ public class AbstractInterceptTest { Log.info("Found interceptor: " + interceptorName); } + protected static void checkInterface(Class testClass, Class interfaceCls) { + Assert.assertTrue("Check interface failure, the test class: " + testClass + " does not implement the expected interface: " + interfaceCls, + EnhancedInstance.class.isAssignableFrom(BizFoo.class)); + } + protected static void checkErrors() { Assert.assertEquals("Error occurred in transform", 0, EnhanceHelper.getErrors().size()); } @@ -142,7 +154,7 @@ public class AbstractInterceptTest { protected void installConstructorInterceptorWithMethodDelegation(String className, int round) { String interceptorClassName = CONSTRUCTOR_INTERCEPTOR_CLASS + "$" + className + "$" + round; String nameTrait = getNameTrait(round); - String fieldName = nameTrait + "_delegate$constructor" + round; + String fieldName = nameTrait + "delegate$" + "constructor" + round; AgentBuilder agentBuilder = newAgentBuilder(nameTrait); agentBuilder.type(ElementMatchers.named(className)) @@ -162,6 +174,36 @@ public class AbstractInterceptTest { .installOn(ByteBuddyAgent.install()); } + protected void installInterface(String className) { + String nameTrait = getNameTrait(1); + newAgentBuilder(nameTrait).type(ElementMatchers.named(className)) + .transform((builder, typeDescription, classLoader, module, protectionDomain) -> { + if (deleteDuplicatedFields) { + builder = builder.visit(new SWAsmVisitorWrapper()); + } + /** + * 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. + * + */ + if (!typeDescription.isAssignableTo(EnhancedInstance.class)) { + builder = builder.defineField( + CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE) + .implement(EnhancedInstance.class) + .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME)); + } + return builder; + } + ) + .with(getListener("EnhancedInstance")) + .installOn(ByteBuddyAgent.install()); + } + protected String getNameTrait(int round) { return nameTraits.get(round - 1); } @@ -173,7 +215,7 @@ public class AbstractInterceptTest { return new SWAgentBuilderDefault(byteBuddy, new SWNativeMethodStrategy(nameTrait)) .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION) - .with(AgentBuilder.DescriptionStrategy.Default.POOL_FIRST) + .with(new SWDescriptionStrategy(nameTrait)) .with(new SWClassFileLocator(ByteBuddyAgent.install(), getClassLoader())); } diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform1Test.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform1Test.java index a33d1bec4..0e33108ff 100644 --- a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform1Test.java +++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform1Test.java @@ -50,6 +50,19 @@ public class ReTransform1Test extends AbstractReTransformTest { checkConstructorInterceptor(BIZ_FOO_CLASS_NAME, 1); checkErrors(); + // installTraceClassTransformer("Trace class: "); + + // do retransform + reTransform(instrumentation, BizFoo.class); + + // test again + callBizFoo(1); + + // check interceptors + checkMethodInterceptor(SAY_HELLO_METHOD, 1); + checkConstructorInterceptor(BIZ_FOO_CLASS_NAME, 1); + + // test ProjectService ProjectService projectService = new ProjectService(); ProjectDO originProjectDO = ProjectDO.builder() .name("test") @@ -59,19 +72,8 @@ public class ReTransform1Test extends AbstractReTransformTest { ProjectDO projectDO = projectService.getById(1); projectService.list(); - // installTraceClassTransformer("Trace class: "); - - // do retransform - reTransform(instrumentation, BizFoo.class); reTransform(instrumentation, ProjectService.class); - // test again - callBizFoo(1); - - // check interceptors - checkMethodInterceptor(SAY_HELLO_METHOD, 1); - checkConstructorInterceptor(BIZ_FOO_CLASS_NAME, 1); - projectDO = projectService.getById(1); Assert.assertEquals(originProjectDO, projectDO); diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform2Test.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform2Test.java index 0dd8749da..c603a6cd7 100644 --- a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform2Test.java +++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform2Test.java @@ -56,6 +56,12 @@ public class ReTransform2Test extends AbstractReTransformTest { // do retransform reTransform(instrumentation, BizFoo.class); +// int retransformCount = 30; +// for (int i = 0; i < retransformCount; i++) { +// reTransform(instrumentation, BizFoo.class); +// // reTransform(instrumentation, ProjectService.class); +// } + // test again callBizFoo(2); // check interceptors diff --git a/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform3Test.java b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform3Test.java new file mode 100644 index 000000000..4f3a01ed6 --- /dev/null +++ b/apm-sniffer/bytebuddy-patch/src/test/java/org/apache/skywalking/apm/agent/bytebuddy/cases/ReTransform3Test.java @@ -0,0 +1,65 @@ +/* + * 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.agent.bytebuddy.cases; + +import net.bytebuddy.agent.ByteBuddyAgent; +import org.apache.skywalking.apm.agent.bytebuddy.biz.BizFoo; +import org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.EnhancedInstance; +import org.junit.Test; + +import java.lang.instrument.Instrumentation; + +public class ReTransform3Test extends AbstractReTransformTest { + + @Test + public void testInterceptConstructor() throws Exception { + Instrumentation instrumentation = ByteBuddyAgent.install(); + + // install transformer + installMethodInterceptor(BIZ_FOO_CLASS_NAME, SAY_HELLO_METHOD, 1); + installConstructorInterceptor(BIZ_FOO_CLASS_NAME, 1); + // implement EnhancedInstance + installInterface(BIZ_FOO_CLASS_NAME); + + // call target class + callBizFoo(1); + + // check interceptors + checkInterface(BizFoo.class, EnhancedInstance.class); + checkMethodInterceptor(SAY_HELLO_METHOD, 1); + checkConstructorInterceptor(BIZ_FOO_CLASS_NAME, 1); + checkErrors(); + + // installTraceClassTransformer("Trace class: "); + + // do retransform + reTransform(instrumentation, BizFoo.class); + + // test again + callBizFoo(1); + + // check interceptors + checkInterface(BizFoo.class, EnhancedInstance.class); + checkMethodInterceptor(SAY_HELLO_METHOD, 1); + checkConstructorInterceptor(BIZ_FOO_CLASS_NAME, 1); + checkErrors(); + } + +} +