1

作为一个开源 Lifecycle Framework API 提供者,我想尽我所能,以隐式的方式隐藏内部设计来提供 Lifecycle API,这样会给 API Client 带来更多的便利。

预计会避免对核心 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);

我对这些方向的困惑:

  1. 对于Core Java Application,看来我们可以修改启动类的main方法来适配agentmain解决方案。还有其他选择吗?
  2. 对于使用 JavaEE Con​​tainer,例如 Glassfish,我可以使用 ByteCodePreprocessor 来修改类字节码,但是我需要创建一些新的类,但我不知道在哪里存储这些新的类文件,或者如何设计或应用一个新的ClassLoader 在预处理类文件期间加载新创建的类文件。

(BTW Lifecycle API 将遵循元驱动的风格,与没有 EntityManager 接口的 JPA 非常接近,目前大部分只是 Annotations 和 CallbackContext 接口和 LifecycleEvent 接口。)

4

1 回答 1

2

好吧,我能想到的唯一其他方法是使用可以在运行时注册的自定义类加载器。这就是像Powermock这样的框架完成繁重工作的方式。但是,这也需要一些设置,但可以通过编程方式完成。

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

但是,这不适用于已加载的类。(您可以破坏父级第一个模式,但这可能会ClassCastException在框架外部的实例上引发 s 。)

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

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

在这个自定义类加载器中,您总是可以返回检测类。

之间的区别在于agentmainpremain,前者在您将代理附加到正在运行的 JVM(通过附加 API)时被调用,而后者在 JVM 启动时在命令行上指定代理时被调用。在运行时注册代理实际上可能是您的解决方案。我链接的博客条目对此进行了很好的描述。

于 2013-11-28T12:36:51.200 回答