如何在类加载上运行我的代码?

时间:2010-10-26 08:25:35

标签: java classloader

是否有可行的方法在Java中加载任何类时运行我自己的代码,而不强制用户明确地手动加载所有类和自定义类加载器?

无论细节如何,只要实现某个接口的类读取其注释将其与另一个类链接,并将该对赋予第三个类。

编辑:哎呀,我会详细说明:我正在做一个事件处理库。我正在做的是让客户端代码执行他们自己的侦听器/事件对,这需要作为一对在我的库中注册。 (嗯,毕竟不是那么久)。

进一步编辑:目前客户端代码需要手动注册这对类/接口,这非常有效。我的意图是将其自动化,我认为将两个类与注释联系起来会有所帮助。接下来,我想摆脱需要始终保持注册列表最新的客户端代码。

PS:静态块不会,因为我的接口被捆绑到一个库中,客户端代码将创建更多的接口。因此,抽象类也不会这样做,因为它必须是一个接口。

2 个答案:

答案 0 :(得分:8)

如果要在接口上建立行为,可以在该接口中使用静态初始化程序。

public interface Foo{

    static{
        // do initializing here
    }

}

我不是说这是一个好习惯,但它肯定会在第一次加载一个实现类时初始化。

更新:接口中的静态块是非法的。改为使用抽象类!

<强>参考:


但是如果我理解你的话,你希望每个实现类初始化一次。这将是棘手的。使用基于接口的解决方案绝对不能做到这一点。您可以使用具有动态初始化程序(或构造函数)的抽象基类来执行此操作,该基类检查所请求的映射是否已存在,如果不存在则添加它,但在构造函数中执行此类操作非常糟糕。

我认为你最干净的选择是在构建时生成代码(通过使用apt或通过字节码分析使用像asm这样的工具进行注释处理),或者在类加载时使用代理来动态创建映射。 / p>


啊,更多输入。很好。因此,客户端使用您的库并根据注释提供映射。然后我会说你的库应该提供一个初始化方法,其中客户端代码可以注册类。像这样:

YourLibrary.getInstance().registerMappedClasses(
    CustomClass1.class,
    CustomClass2.class,
    CustomClass3.class,
    CustomClass4.class
)

或者更好的是,一个包扫描机制(可以找到实现它的示例代码at this question):

YourLibrary.getInstance().registerMappedClassesFromPackages(
    "com.mycompany.myclientcode.abc",
    "com.mycompany.myclientcode.def"
)

无论如何,基本上没有办法避免让你的客户做那种工作,因为你无法控制他们的构建过程或他们的类加载器(但你当然可以提供类加载器或构建配置的指南)。

答案 1 :(得分:2)

如果你想在任何类加载上运行一些代码,你应该:

  1. 覆盖ClassLoader,在loadClass方法中添加自己的自定义代码(不要忘记在自定义代码之前或之前转发到父ClassLoader)。
  2. 将此自定义ClassLoader定义为您系统的默认值(此处您已了解如何操作:How to set my custom class loader to be the default?)。
  3. 运行并检查。
  4. 根据您的环境类型,有可能不是所有类都被自定义ClassLoader加载(一些实用程序包使用自己的CL,一些Java EE容器处理一些具有特定classLoaders的空间区域等) ,但这是对你所要求的一种近似。