向班级添加字段会导致“ 没有定义索引2“异常

问题描述 投票:0回答:1

我试图向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)

我正在尝试做什么?如果是这样,我错过了什么?

java tomcat byte-buddy
1个回答
0
投票

字段代理只能与MethodDelegation一起使用,而不能与Advice一起使用。对于建议,您可以将自定义注释绑定到字段描述。使用Advice.withCustomBindings来执行此操作。

要表示在运行时定义的字段,请创建fielddescription.latent。

© www.soinside.com 2019 - 2024. All rights reserved.