当前位置: 首页 > 知识库问答 >
问题:

加载某些类时不调用ClassFileTransformer.Transform()

朱建弼
2023-03-14

我试图用Javaflow(http://commons.apache.org/sandbox/commons-javaflow/)和OW2 ASM库(http://ASM.OW2.org/)来测试java类。我设置了javaagent并使用instrumentation.addTransformer()在加载时将我的transformer注册到instrument类。在transformer内部,我检查类是否需要检测。如果是,则执行检测。

症状:总而言之:在加载和检测某些类之后,不会在类加载时调用transform()。

更详细的说:一切都运行得很好。premain被正确调用,我的transformer在加载的前几个类上被调用。在一个特定的类(比如Foo)被工具化之后,事情突然开始变得非常糟糕。我可以看到正在加载类(通过-verbose:class消息),但是没有在这些类上调用transform()方法。这些类是可修改的。如果我选择不对类Foo进行检测,那么所有其他类都将被正确加载和检测。

更多可能对诊断问题有用的信息:1。我在想,在检测类foo时,可能在transform()中引发了一些html" target="_blank">异常。然后我将transform()中的代码包含在try-catch语句中。然而,没有发现任何例外情况。2.看来不是只有Foo类才能触发问题。其他一些类(我不需要检测,但为了测试目的而检测的类)也会触发这个问题。我在可能引发这个问题的类之间找不到太多相似之处。3.如果在transform()内部,我不执行任何检测,所有类负载都由transform()正确地挂钩。

有人知道是什么引起了这个问题吗?如果有必要,我可以提供更多关于我在做什么的信息。

更新:显示症状的最小示例:目录结构如下:

src\
    instrumentation\
        Instrumentor.java
    test\
        InstrumentationTest.java
        TestRunnable.java
lib\
    asm-4.0.jar
    asm-commons-4.0.jar
    asm-util-4.0.jar
    commons-logging-1.1.3.jar
    asm-analysis-4.0.jar
    asm-tree-4.0.jar
    commons-javaflow-2.0-SNAPSHOT.jar
package instrumentation;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;

import org.apache.commons.javaflow.bytecode.transformation.ResourceTransformer;
import org.apache.commons.javaflow.bytecode.transformation.asm.AsmClassTransformer;

public class Instrumentor implements ClassFileTransformer {
    public static void premain(String agentArguments,
        Instrumentation instrumentation) {
        try {
            System.out.println("Executing premain");
            instrumentation.addTransformer(new Instrumentor());
        } catch (Exception e) {
            System.out.println("Exception.");
            e.printStackTrace();
        }
    }

    static String[] toInstrument = new String[] { "test/InstrumentationTest", "test/TestRunnable" };

    // static String[] toInstrument = new String[] { "test/TestRunnable" };

    @Override
    public byte[] transform(ClassLoader loader, String className,
        Class redefiningClass, ProtectionDomain domain, byte[] bytes)
        throws IllegalClassFormatException {
        try {
            ResourceTransformer continuationTransformer = new AsmClassTransformer();
            if (className.equals("test/TestRunnable") || className.equals("test/InstrumentationTest")) {
                System.out.println(className + " intercepted.");
            }
            for (String ti : toInstrument) {
                if (className.equals(ti)) {
                    System.out.println("Instrumenting " + className);
                    byte[] continuationClass = continuationTransformer.transform(bytes);
                    return continuationClass;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        // System.out.println("Not instrumented. " + className);
        return bytes;
    }
}
package test;
public class InstrumentationTest {
    public static void main(String args[]) {
        Runnable r = new TestRunnable();
        r.run();
    }
}
package test;
public class TestRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++)
            System.out.println(i);
    }
}

下面是构建文件示例:

<?xml version="1.0" encoding="UTF-8"?>
<project name="project" default="package" basedir=".">
  <fileset id="lib" dir="lib" includes="**/*.jar"/>
  <pathconvert property="libs" refid="lib" pathsep=":" />
  <target name="compile" description="compile class files.">
    <mkdir dir="build/classes" />
    <javac srcdir="src" destdir="build/classes" debug="true" debuglevel="lines,vars,source">
      <classpath>
        <fileset dir="lib" includes="**/*.jar" />
      </classpath>
    </javac>
  </target>
  <target name="package" description="build the jar file from the compiled classes." depends="compile">
    <mkdir dir="build" />
    <jar jarfile="build/agent.jar" basedir="build/classes">
      <manifest>
        <attribute name="Premain-Class" value="instrumentation.Instrumentor" />
      </manifest>
    </jar>
  </target>
  <target name="run" description="run the test" depends="package" >
    <java fork="true" classname="test.InstrumentationTest">
      <classpath>
        <fileset dir="lib" includes="**/*.jar" />
        <pathelement path="./build/classes" />
      </classpath>
      <jvmarg value="-Xbootclasspath/p:${libs}" />
      <jvmarg value="-javaagent:./build/agent.jar" />
    </java>
  </target>
  <target name="clean">
    <delete dir="build" />
  </target>
</project>

然后,如果运行“Ant run”,您会发现只有InstrumentationTest被检测,而TestRunnable没有检测(transform()甚至没有拦截它的负载)。您可以切换toInstrument数组上的注释,以查看如果InstrumentationTest未检测,则transform()会正确地截取所有类的负载,并检测TestRunnable。

共有1个答案

韦睿
2023-03-14

您有没有注意到在“instrumentation.addTransformer”方法的javadoc中,它说:“所有将来的类定义都将被transformer看到,但任何注册的transformer所依赖的类的定义除外。”

你的案子是不是陷入了这种情况?

 类似资料:
  • 图像加载: 链接1:https://freshtocook.in/uploads/banner/47a16ffc2fc5935dccd37574083c6201.jpg 链接2:https://freshtocook.in/uploads/banner/7eecf823e008a0bb93f347d994b6e534.jpg

  • 问题内容: 我的问题很简单,如何使用jquery ajax comand检索某些div 喜欢带负载 问题答案: 如果div是AJAX响应的一部分:

  • 我正在阅读Horstmann撰写的《Java核心》第10卷中关于断言的第四章,内容是: 有些类不是由类加载器加载的,而是由虚拟机直接加载的。您可以使用这些开关有选择地启用或禁用这些类中的断言。 我对此感到困惑,哪些类将由JVM加载,而不是由类加载器加载,我认为引导类加载器加载了初始类? 谢谢

  • 首先,我使用Windows 7 64位,WAMP 32位和火鸟32位。 我试图使用PHP与火鸟或interbase,所以我取消注释以下行从我的php.ini文件: 然后,当我启动WAMP时,会出现以下错误: 我已经尝试过的: 有人知道我该怎么解决这个问题吗?谢谢

  • 无法在WebView中加载以下网页 https://6awlanow.com/about/faqs 到目前为止,我一直在努力- 我已经提供了互联网许可。除了在WebView上,URL在任何地方都可以正常加载。我得到以下错误- 在我的控制台上获取以下信息-

  • 我对JSF有一个非常奇怪的问题,但我不能自己解决它,因为没有错误消息我可以谷歌搜索。问题是,我有一个视图提交一个新的文章或更新一个现有的文章。 方法getArticle()返回-if?id=x是通过url设置的-id为x的文章POJO。否则,一个纯粹的空的新文章。根据设置的id,模式editArticle被设置为true或false。 我使用了BalusC的检查表(在JSF中没有调用action方