我试图向java.sql.Connection类型的子类添加一个字段,以便监视长时间打开的连接(例如连接泄漏)。
这就是我想要运行的:
public class TransactionMonitorVisitor {
interface FieldSetter {
void setField(String value);
}
interface FieldGetter {
String getValue();
}
public static class ConnectionConstructorVisitor {
@Advice.OnMethodExit
public static void intercept(@Advice.Origin Constructor<?> constructor,
@Advice.This Object obj,
@FieldProxy("__txUuid__") FieldSetter accessor
) {
String txUuid = UUID.randomUUID().toString();
System.out.println("Visiting constructor: txUuid=" + txUuid + ", obj=" + obj);
accessor.setField(txUuid);
}
}
public static class ConnectionMethodVisitor {
@Advice.OnMethodExit
public static void intercept(@Advice.Origin Method method,
@FieldProxy("__txUuid__") FieldGetter accessor
) {
String methodName = method.getName();
String txUuid = accessor.getValue();
System.out.println("Visiting method: txUuid=" + txUuid + ", method=" + methodName);
}
}
public static void installOn(Instrumentation instrumentation) throws Exception {
new AgentBuilder.Default()
.type(ElementMatchers.isSubTypeOf(Connection.class))
.transform((builder, typeDescription, classLoader, javaModule) ->
builder.defineField("__txUuid__", String.class)
.visit(Advice.to(ConnectionConstructorVisitor.class).on((ElementMatchers.isConstructor())))
.visit(Advice.to(ConnectionMethodVisitor.class).on(ElementMatchers.nameMatches("commit|rollback|close")))
)
.with(AgentBuilder.Listener.StreamWriting.toSystemError())
.installOn(instrumentation);
System.out.println("Installed :: " + TransactionMonitorVisitor.class.getName());
}
}
当我启动我的应用程序(Tomcat中的Web应用程序)时,我收到以下错误:
java.lang.IllegalStateException: net.sourceforge.jtds.jdbc.ConnectionJDBC3(java.lang.String,java.util.Properties) throws java.sql.SQLException does not define an index 2
at net.bytebuddy.asm.Advice$OffsetMapping$ForArgument$Unresolved.resolve(Advice.java:1551)
at net.bytebuddy.asm.Advice$OffsetMapping$ForArgument.resolve(Advice.java:1462)
at net.bytebuddy.asm.Advice$OffsetMapping$ForArgument$Unresolved.resolve(Advice.java:1564)
at net.bytebuddy.asm.Advice$Dispatcher$Inlining$Resolved$ForMethodExit.apply(Advice.java:5818)
at net.bytebuddy.asm.Advice$Dispatcher$Inlining$Resolved$AdviceMethodInliner.visitMethod(Advice.java:5414)
at net.bytebuddy.jar.asm.ClassReader.b(Unknown Source)
at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source)
at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source)
at net.bytebuddy.asm.Advice$Dispatcher$Inlining$Resolved$AdviceMethodInliner.doApply(Advice.java:5408)
at net.bytebuddy.asm.Advice$Dispatcher$Inlining$Resolved$ForMethodExit$AdviceMethodInliner.apply(Advice.java:5902)
at net.bytebuddy.asm.Advice$AdviceVisitor$WithExitAdvice.onUserEnd(Advice.java:7503)
at net.bytebuddy.asm.Advice$AdviceVisitor.visitMaxs(Advice.java:7251)
at net.bytebuddy.jar.asm.ClassReader.a(Unknown Source)
at net.bytebuddy.jar.asm.ClassReader.b(Unknown Source)
at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source)
at net.bytebuddy.jar.asm.ClassReader.accept(Unknown Source)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForInlining.create(TypeWriter.java:2941)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1633)
at net.bytebuddy.dynamic.scaffold.inline.RebaseDynamicTypeBuilder.make(RebaseDynamicTypeBuilder.java:200)
at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:8902)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:9303)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9266)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1300(AgentBuilder.java:9044)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9622)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9572)
at ...
基于一些研究,我已经尝试添加.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
,但这给我带来了与上面相同的错误。
我看到另一个地方使用.disableClassFormatChanges()
和RedefinitionStrategy.RETRANSFORMATION
,但这仍然没有让我没有错误。新错误是这样的:
java.lang.IllegalStateException: Cannot define field for frozen type: class net.sourceforge.jtds.jdbc.ConnectionJDBC3
at net.bytebuddy.dynamic.scaffold.InstrumentedType$Frozen.withField(InstrumentedType.java:1149)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Adapter$FieldDefinitionAdapter.materialize(DynamicType.java:3159)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.visit(DynamicType.java:2571)
at com.calabrio.athena.tx.TransactionMonitorVisitor.lambda$installOn$0(TransactionMonitorVisitor.java:70)
at com.calabrio.athena.tx.TransactionMonitorVisitor$$Lambda$1/1528637575.transform(Unknown Source)
at net.bytebuddy.agent.builder.AgentBuilder$Transformer$Compound.transform(AgentBuilder.java:2335)
at net.bytebuddy.agent.builder.AgentBuilder$Default$Transformation$Simple$Resolution.apply(AgentBuilder.java:8899)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.doTransform(AgentBuilder.java:9303)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.transform(AgentBuilder.java:9266)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer.access$1300(AgentBuilder.java:9044)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9622)
at net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer$LegacyVmDispatcher.run(AgentBuilder.java:9572)
我正在尝试做什么?如果是这样,我错过了什么?
字段代理只能与MethodDelegation一起使用,而不能与Advice一起使用。对于建议,您可以将自定义注释绑定到字段描述。使用Advice.withCustomBindings来执行此操作。
要表示在运行时定义的字段,请创建fielddescription.latent。