序
本文主要研究一下skywalking的AbstractPlatformTransactionManagerInstrumentation
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 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 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继承了ClassInstanceMethodsEnhancePluginDefine,其getInstanceMethodsInterceptPoints方法创建了InstanceMethodsInterceptPoint数组,其中一个InstanceMethodsInterceptPoint的getMethodsMatcher为named("getTransaction"),getMethodsInterceptor返回org.apache.skywalking.apm.plugin.spring.transaction.GetTransactionMethodInterceptor;另外一个InstanceMethodsInterceptPoint的getMethodsMatcher为named("commit").or(named("rollback"),getMethodsInterceptor返回的是org.apache.skywalking.apm.plugin.spring.transaction.EndTransactionMethodInterceptor;其enhanceClass方法返回的是byName("org.springframework.transaction.support.AbstractPlatformTransactionManager")
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;
}
}
- ClassInstanceMethodsEnhancePluginDefine继承了ClassEnhancePluginDefine,其getStaticMethodsInterceptPoints方法返回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.
*
* 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 (!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 junction = not(isStatic()).and(instanceMethodsInterceptPoint.getMethodsMatcher());
if (instanceMethodsInterceptPoint instanceof DeclaredInstanceMethodsInterceptPoint) {
junction = junction.and(ElementMatchers.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继承了AbstractClassEnhancePluginDefine,其enhance方法先执行enhanceClass(typeDescription, newClassBuilder, classLoader),后执行enhanceInstance(typeDescription, newClassBuilder, classLoader, context),最后返回newClassBuilder;enhanceClass方法遍历staticMethodsInterceptPoints,通过newClassBuilder.method(isStatic().and(staticMethodsInterceptPoint.getMethodsMatcher())).intercept方法增强newClassBuilder;enhanceInstance方法主要用于增强CONTEXT_ATTR_NAME字段、constructors、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实现了InstanceMethodsAroundInterceptor接口,其beforeMethod方法会获取TransactionDefinition,然后通过ContextManager.createLocalSpan创建span,然后设置Constants.TAG_SPRING_TRANSACTION_ISOLATION_LEVEL、Constants.TAG_SPRING_TRANSACTION_PROPAGATION_BEHAVIOR、Constants.TAG_SPRING_TRANSACTION_TIMEOUT这几个tag;afterMethod方法执行ContextManager.stopSpan();handleMethodException方法则执行ContextManager.activeSpan().errorOccurred().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);
}
}
- EndTransactionMethodInterceptor实现了InstanceMethodsAroundInterceptor接口,其beforeMethod方法通过ContextManager.createLocalSpan创建span,然后获取TransactionStatus,之后设置Constants.TAG_SPRING_TRANSACTION_IS_NEW_TRANSACTION、Constants.TAG_SPRING_TRANSACTION_HAS_SAVEPOINT、Constants.TAG_SPRING_TRANSACTION_ROLLBACK_ONLY、Constants.TAG_SPRING_TRANSACTION_IS_COMPLETED这几个tag;其afterMethod方法执行ContextManager.stopSpan();其handleMethodException方法执行ContextManager.activeSpan().errorOccurred().log(t)
小结
AbstractPlatformTransactionManagerInstrumentation继承了ClassInstanceMethodsEnhancePluginDefine,其getInstanceMethodsInterceptPoints方法创建了InstanceMethodsInterceptPoint数组,其中一个InstanceMethodsInterceptPoint的getMethodsMatcher为named("getTransaction"),getMethodsInterceptor返回org.apache.skywalking.apm.plugin.spring.transaction.GetTransactionMethodInterceptor;另外一个InstanceMethodsInterceptPoint的getMethodsMatcher为named("commit").or(named("rollback"),getMethodsInterceptor返回的是org.apache.skywalking.apm.plugin.spring.transaction.EndTransactionMethodInterceptor;其enhanceClass方法返回的是byName("org.springframework.transaction.support.AbstractPlatformTransactionManager")
doc
- AbstractPlatformTransactionManagerInstrumentation