order
This paper mainly studies the AbstractPlatformTransactionManagerInstrumentation of skywalking
AbstractPlatformTransactionManagerInstrumentation
skywalking-6.6.0/apm-sniffer/optional-plugins/optional-spring-plugins/spring-tx-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/transaction/define/AbstractPlatformTransactionManagerInstrumentation.java
public class AbstractPlatformTransactionManagerInstrumentation extends ClassInstanceMethodsEnhancePluginDefine { @Override public ConstructorInterceptPoint[] getConstructorsInterceptPoints() { return new ConstructorInterceptPoint[0]; } @Override public InstanceMethodsInterceptPoint[] getInstanceMethodsInterceptPoints() { return new InstanceMethodsInterceptPoint[]{ new InstanceMethodsInterceptPoint() { @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { return named("getTransaction"); } @Override public String getMethodsInterceptor() { return "org.apache.skywalking.apm.plugin.spring.transaction.GetTransactionMethodInterceptor"; } @Override public boolean isOverrideArgs() { return false; } }, new InstanceMethodsInterceptPoint() { @Override public ElementMatcher<MethodDescription> getMethodsMatcher() { return named("commit").or(named("rollback")); } @Override public String getMethodsInterceptor() { return "org.apache.skywalking.apm.plugin.spring.transaction.EndTransactionMethodInterceptor"; } @Override public boolean isOverrideArgs() { return false; } } }; } @Override public ClassMatch enhanceClass() { return byName("org.springframework.transaction.support.AbstractPlatformTransactionManager"); } }
- AbstractPlatformTransactionManagerInstrumentation inherits classinstancemethods enhanceplugindefine, and its getinstancemethods interceptpoints method creates an array of instancemethods interceptpoint. The getMethodsMatcher of one instancemethods interceptpoint is named("getTransaction"), and getmethodsinterpoint returns org.apache.skywalking.apm.plugin.spring.tra Nsaction.gettransactionmethodinterceptor; getMethodsMatcher of another instancemethodinterceptpoint is named("commit").or(named("rollback"), getMethodsInterceptor returns org.apache.skywalking.apm.plugin.spring.transaction.EndTransactionMethodInterceptor; its enhanceClass method returns byname ("org. Springframework. Transaction. Support. ABS tractPlatformTransactionManager")
ClassInstanceMethodsEnhancePluginDefine
skywalking-6.6.0/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassInstanceMethodsEnhancePluginDefine.java
public abstract class ClassInstanceMethodsEnhancePluginDefine extends ClassEnhancePluginDefine { /** * @return null, means enhance no static methods. */ @Override public StaticMethodsInterceptPoint[] getStaticMethodsInterceptPoints() { return null; } }
- Classinstancemethods enhanceplugindefine inherits ClassEnhancePluginDefine, whose getstaticmethodsinterpoints method returns null
ClassEnhancePluginDefine
skywalking-6.6.0/apm-sniffer/apm-agent-core/src/main/java/org/apache/skywalking/apm/agent/core/plugin/interceptor/enhance/ClassEnhancePluginDefine.java
public abstract class ClassEnhancePluginDefine extends AbstractClassEnhancePluginDefine { private static final ILog logger = LogManager.getLogger(ClassEnhancePluginDefine.class); /** * New field name. */ public static final String CONTEXT_ATTR_NAME = "_$EnhancedClassField_ws"; /** * Begin to define how to enhance class. After invoke this method, only means definition is finished. * * @param typeDescription target class description * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. * @return new byte-buddy's builder for further manipulation. */ @Override protected DynamicType.Builder<?> enhance(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException { newClassBuilder = this.enhanceClass(typeDescription, newClassBuilder, classLoader); newClassBuilder = this.enhanceInstance(typeDescription, newClassBuilder, classLoader, context); return newClassBuilder; } /** * Enhance a class to intercept constructors and class instance methods. * * @param typeDescription target class description * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. * @return new byte-buddy's builder for further manipulation. */ private DynamicType.Builder<?> enhanceInstance(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader, EnhanceContext context) throws PluginException { ConstructorInterceptPoint[] constructorInterceptPoints = getConstructorsInterceptPoints(); InstanceMethodsInterceptPoint[] instanceMethodsInterceptPoints = getInstanceMethodsInterceptPoints(); String enhanceOriginClassName = typeDescription.getTypeName(); boolean existedConstructorInterceptPoint = false; if (constructorInterceptPoints != null && constructorInterceptPoints.length > 0) { existedConstructorInterceptPoint = true; } boolean existedMethodsInterceptPoints = false; if (instanceMethodsInterceptPoints != null && instanceMethodsInterceptPoints.length > 0) { existedMethodsInterceptPoints = true; } /** * nothing need to be enhanced in class instance, maybe need enhance static methods. */ if (!existedConstructorInterceptPoint && !existedMethodsInterceptPoints) { return newClassBuilder; } /** * Manipulate class source code.<br/> * * new class need:<br/> * 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 (!context.isObjectExtended()) { newClassBuilder = newClassBuilder.defineField(CONTEXT_ATTR_NAME, Object.class, ACC_PRIVATE | ACC_VOLATILE) .implement(EnhancedInstance.class) .intercept(FieldAccessor.ofField(CONTEXT_ATTR_NAME)); context.extendObjectCompleted(); } /** * 2. enhance constructors */ if (existedConstructorInterceptPoint) { for (ConstructorInterceptPoint constructorInterceptPoint : constructorInterceptPoints) { if (isBootstrapInstrumentation()) { newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()).intercept(SuperMethodCall.INSTANCE .andThen(MethodDelegation.withDefaultConfiguration() .to(BootstrapInstrumentBoost.forInternalDelegateClass(constructorInterceptPoint.getConstructorInterceptor())) ) ); } else { newClassBuilder = newClassBuilder.constructor(constructorInterceptPoint.getConstructorMatcher()).intercept(SuperMethodCall.INSTANCE .andThen(MethodDelegation.withDefaultConfiguration() .to(new ConstructorInter(constructorInterceptPoint.getConstructorInterceptor(), classLoader)) ) ); } } } /** * 3. enhance instance methods */ if (existedMethodsInterceptPoints) { for (InstanceMethodsInterceptPoint instanceMethodsInterceptPoint : instanceMethodsInterceptPoints) { String interceptor = instanceMethodsInterceptPoint.getMethodsInterceptor(); if (StringUtil.isEmpty(interceptor)) { throw new EnhanceException("no InstanceMethodsAroundInterceptor define to enhance class " + enhanceOriginClassName); } ElementMatcher.Junction<MethodDescription> junction = not(isStatic()).and(instanceMethodsInterceptPoint.getMethodsMatcher()); if (instanceMethodsInterceptPoint instanceof DeclaredInstanceMethodsInterceptPoint) { junction = junction.and(ElementMatchers.<MethodDescription>isDeclaredBy(typeDescription)); } if (instanceMethodsInterceptPoint.isOverrideArgs()) { if (isBootstrapInstrumentation()) { newClassBuilder = newClassBuilder.method(junction) .intercept( MethodDelegation.withDefaultConfiguration() .withBinders( Morph.Binder.install(OverrideCallable.class) ) .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)) ); } else { newClassBuilder = newClassBuilder.method(junction) .intercept( MethodDelegation.withDefaultConfiguration() .withBinders( Morph.Binder.install(OverrideCallable.class) ) .to(new InstMethodsInterWithOverrideArgs(interceptor, classLoader)) ); } } else { if (isBootstrapInstrumentation()) { newClassBuilder = newClassBuilder.method(junction) .intercept( MethodDelegation.withDefaultConfiguration() .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)) ); } else { newClassBuilder = newClassBuilder.method(junction) .intercept( MethodDelegation.withDefaultConfiguration() .to(new InstMethodsInter(interceptor, classLoader)) ); } } } } return newClassBuilder; } /** * Enhance a class to intercept class static methods. * * @param typeDescription target class description * @param newClassBuilder byte-buddy's builder to manipulate class bytecode. * @return new byte-buddy's builder for further manipulation. */ private DynamicType.Builder<?> enhanceClass(TypeDescription typeDescription, DynamicType.Builder<?> newClassBuilder, ClassLoader classLoader) throws PluginException { StaticMethodsInterceptPoint[] staticMethodsInterceptPoints = getStaticMethodsInterceptPoints(); String enhanceOriginClassName = typeDescription.getTypeName(); if (staticMethodsInterceptPoints == null || staticMethodsInterceptPoints.length == 0) { return newClassBuilder; } for (StaticMethodsInterceptPoint staticMethodsInterceptPoint : staticMethodsInterceptPoints) { String interceptor = staticMethodsInterceptPoint.getMethodsInterceptor(); if (StringUtil.isEmpty(interceptor)) { throw new EnhanceException("no StaticMethodsAroundInterceptor define to enhance class " + enhanceOriginClassName); } if (staticMethodsInterceptPoint.isOverrideArgs()) { if (isBootstrapInstrumentation()) { newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher())) .intercept( MethodDelegation.withDefaultConfiguration() .withBinders( Morph.Binder.install(OverrideCallable.class) ) .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)) ); } else { newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher())) .intercept( MethodDelegation.withDefaultConfiguration() .withBinders( Morph.Binder.install(OverrideCallable.class) ) .to(new StaticMethodsInterWithOverrideArgs(interceptor)) ); } } else { if (isBootstrapInstrumentation()) { newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher())) .intercept( MethodDelegation.withDefaultConfiguration() .to(BootstrapInstrumentBoost.forInternalDelegateClass(interceptor)) ); } else { newClassBuilder = newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher())) .intercept( MethodDelegation.withDefaultConfiguration() .to(new StaticMethodsInter(interceptor)) ); } } } return newClassBuilder; } }
- ClassEnhancePluginDefine inherits AbstractClassEnhancePluginDefine. Its enhancemethod first implements enhanceClass(typeDescription, newClassBuilder, classLoader), then enhanceInstance(typeDescription, newClassBuilder, classLoader, context), and finally return the newClassBuilder; enhanceClass method to traverse the staticmethodsinterpoints, and enhance the newClassBuilder through the newClassBuilder. Method (isstatic(). And (staticmethodsinterpoint. Getmethodsmatcher()). Intercept method; enhanceInstance method is mainly used to enhance the context? Attr? Name field, constructors, and instance methods
GetTransactionMethodInterceptor
skywalking-6.6.0/apm-sniffer/optional-plugins/optional-spring-plugins/spring-tx-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/transaction/GetTransactionMethodInterceptor.java
public class GetTransactionMethodInterceptor implements InstanceMethodsAroundInterceptor { @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable { if (allArguments[0] == null) { AbstractSpan span = ContextManager.createLocalSpan(Constants.OPERATION_NAME_SPRING_TRANSACTION_NO_TRANSACTION_DEFINITION_GIVEN); span.setComponent(ComponentsDefine.SPRING_TX); return; } TransactionDefinition definition = (TransactionDefinition) allArguments[0]; AbstractSpan span = ContextManager.createLocalSpan(Constants.OPERATION_NAME_SPRING_TRANSACTION_GET_TRANSACTION_METHOD + buildOperationName(definition.getName())); span.tag(Constants.TAG_SPRING_TRANSACTION_ISOLATION_LEVEL, String.valueOf(definition.getIsolationLevel())); span.tag(Constants.TAG_SPRING_TRANSACTION_PROPAGATION_BEHAVIOR, String.valueOf(definition.getPropagationBehavior())); span.tag(Constants.TAG_SPRING_TRANSACTION_TIMEOUT, String.valueOf(definition.getTimeout())); span.setComponent(ComponentsDefine.SPRING_TX); } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { ContextManager.stopSpan(); return ret; } @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) { ContextManager.activeSpan().errorOccurred().log(t); } private String buildOperationName(String transactionDefinitionName) { if (!Config.Plugin.SpringTransaction.SIMPLIFY_TRANSACTION_DEFINITION_NAME) { return transactionDefinitionName; } String[] ss = transactionDefinitionName.split("\\."); int simplifiedLength = ss.length - 2; if (simplifiedLength < 0) { return transactionDefinitionName; } StringBuilder name = new StringBuilder(); for (int i = 0; i < ss.length - 1; i++) { name.append(i < simplifiedLength ? ss[i].charAt(0) : ss[i]).append("."); } return name.append(ss[ss.length - 1]).toString(); } }
- GetTransactionMethodInterceptor implements the instancemethods aroundinterceptor interface. Its beforeMethod method will get the TransactionDefinition, then create span through ContextManager.createLocalSpan, and then set constants.tag'spring'transaction'isolation'level, constants.tag'spring'transaction'promotion'behavior, constants.tag'spring'transaction'timeout These tags; afterMethod methods execute ContextManager.stopSpan(); handleMethodException methods execute contextmanager. Activespan(). Erroreoccurred(). Log (T)
EndTransactionMethodInterceptor
skywalking-6.6.0/apm-sniffer/optional-plugins/optional-spring-plugins/spring-tx-plugin/src/main/java/org/apache/skywalking/apm/plugin/spring/transaction/EndTransactionMethodInterceptor.java
public class EndTransactionMethodInterceptor implements InstanceMethodsAroundInterceptor { @Override public void beforeMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, MethodInterceptResult result) throws Throwable { AbstractSpan span = ContextManager.createLocalSpan(Constants.OPERATION_NAME_SPRING_TRANSACTION_PREFIX + method.getName()); TransactionStatus status = (TransactionStatus) allArguments[0]; span.tag(Constants.TAG_SPRING_TRANSACTION_IS_NEW_TRANSACTION, String.valueOf(status.isNewTransaction())); span.tag(Constants.TAG_SPRING_TRANSACTION_HAS_SAVEPOINT, String.valueOf(status.hasSavepoint())); span.tag(Constants.TAG_SPRING_TRANSACTION_ROLLBACK_ONLY, String.valueOf(status.isRollbackOnly())); span.tag(Constants.TAG_SPRING_TRANSACTION_IS_COMPLETED, String.valueOf(status.isCompleted())); span.setComponent(ComponentsDefine.SPRING_TX); } @Override public Object afterMethod(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Object ret) throws Throwable { ContextManager.stopSpan(); return ret; } @Override public void handleMethodException(EnhancedInstance objInst, Method method, Object[] allArguments, Class<?>[] argumentsTypes, Throwable t) { ContextManager.activeSpan().errorOccurred().log(t); } }
- The EndTransactionMethodInterceptor implements the instancemethods aroundinterceptor interface. Its beforeMethod method creates a span through ContextManager.createLocalSpan, obtains the TransactionStatus, and then sets constants.tag'spring'transaction'is'new'transaction, constants.tag'spring'transaction'has'savepoint, constants.tag'spring'transaction'rollback'only, Co Nstants. Tag? Spring? Transaction? Is? Completed; its afterMethod method executes ContextManager.stopSpan(); its handleMethodException method executes contextmanager. Activespan(). Erroreoccurred(). Log (T)
Summary
AbstractPlatformTransactionManagerInstrumentation inherits classinstancemethods enhanceplugindefine, and its getinstancemethods interceptpoints method creates an array of instancemethods interceptpoint. The getMethodsMatcher of one instancemethods interceptpoint is named("getTransaction"), and getmethodsinterpoint returns org.apache.skywalking.apm.plugin.spring.tra Nsaction.gettransactionmethodinterceptor; getMethodsMatcher of another instancemethodinterceptpoint is named("commit").or(named("rollback"), getMethodsInterceptor returns org.apache.skywalking.apm.plugin.spring.transaction.EndTransactionMethodInterceptor; its enhanceClass method returns byname ("org. Springframework. Transaction. Support. ABS tractPlatformTransactionManager")