有没有关于Load Time Bytecode Transformation的解决方案,而没有在java命令行中指定javaagent选项

时间:2013-11-27 14:20:00

标签: java glassfish classloader bytecode load-time-weaving

作为开源生命周期框架API提供商,我想尽量以隐式方式隐藏内部设计以提供生命周期API,这样可以为API客户端带来更多便利。

预计将避免对Core Java应用程序和Java EE应用程序进行配置,但实际情况是我使用java命令-javaagent:$ {path} /Lifecycle.jar选项在类加载时启用我自己的ClassFileTransformer时间。

经过一些搜索后,发现了一些不明确的方向。我需要一些Java Guy来总结和指导我们。

  1. agentmain vs premain
  2. 与指定的运行时环境集成,例如Glassfish的ByteCodePreprocessor,它具有以下执行字节代码转换的方法:

    public byte[] preprocess(String classname, byte[] classBytes);

  3. 我对这些方向的困惑:

    1. 对于Core Java Application,似乎我们可以修改启动类的主要方法以适应代理主域解决方案。还有其他选择吗?
    2. 对于使用JavaEE容器,比如Glassfish,我可以使用ByteCodePreprocessor来修改类字节代码,但我需要创建一些新类,但我不知道在哪里存储这些新类文件,或者如何设计或在预处理类文件期间应用新的ClassLoader来加载新创建的类文件。
    3. (BTW Lifecycle API将遵循元驱动的风格,与JPA非常接近,没有EntityManager接口,现在大多数只是Annotations和CallbackContext接口以及LifecycleEvent接口。)

1 个答案:

答案 0 :(得分:2)

嗯,我能想到的唯一其他方法是使用自定义类加载器,您可以在运行时注册。这就是像Powermock这样的框架如何解决这些问题。但是,这也需要一些设置,但可以以编程方式完成。

只要您的框架具有明确定义的入口点,并且只要所有代码都在您的应用程序中运行,您就可以应用自定义类加载器,它可以检测所有已加载的类。

但是,这对已经加载的类不起作用。 (您可以打破父级第一个patern,但这可能会在框架外部的实例上引发ClassCastException。)

避免这种情况需要覆盖同样详细的系统类加载器。为了完整起见,这里是ClassLoader.getSystemClassLoader的javadoc的摘录:

  

如果在此时定义了系统属性“java.system.class.loader”   首先调用方法,然后取该属性的值   将作为系统类加载器返回的类的名称。   该类使用默认的系统类加载器加载并且必须   定义一个公共构造函数,它接受一个类型的参数   ClassLoader,用作委托父级。一个例子是   然后使用此构造函数创建默认系统类   loader作为参数。生成的类加载器定义为   系统类加载器。

在这个自定义类加载器中,您可以随时返回已检测的类。

difference between agentmain and premain是在将代理附加到正在运行的JVM(via the attach API)时调用前者,而如果在JVM启动时在命令行上指定了代理,则调用后者。在运行时注册代理可能实际上是一个解决方案。我链接的博客条目提供了很好的描述。