需要在运行时通过动态生成和编译的java .class文件替换运行时的现有类

时间:2014-06-16 12:08:35

标签: java reflection code-generation dynamic-class-loaders runtime-compilation

我的目的是在运行时动态地将新属性+ getter setter方法注入类定义。目前我有一个方法用新添加的属性重新生成代码,然后编译生成的代码。

最初,我会在编译时为每个类创建一个模板。运行项目后,模板类将加载到运行时。我编写了一些代码来动态生成java代码并编译它。当我使用下面的代码加载新创建的类时,我无法访问注入的方法。我想我无法覆盖现有的运行时定义。我经历了很多博客,但仍然无法理解为什么。请帮忙。

我正在访问DROOLS中新添加的方法,并且在任何其他类中都没有引用它,这可能会在编译期间引发问题。具有新属性的规则引擎的规则在运行时更新,因此我需要相应地调整我的代码。下面是ClassLoader代码。此代码不会抛出任何异常,但无法解决我的目的。不确定编码是否正确。

public static boolean loadClass2RunTime() {
    try {
        File folder = new File("target");
        File dir = new File(folder, "com/itap/template");
        File[] classFiles = dir.listFiles();
        URL[] url = new URL[] { folder.toURI().toURL() };

        int i = 0;
        for (File classFile : classFiles) {
            if (classFile.getName().matches(".*\\.class")) {
                System.out.println(classFile.getName().substring(0,
                        classFile.getName().lastIndexOf(".")));

                ClassLoader loader = URLClassLoader
                        .newInstance(new URL[] { folder.toURI().toURL() });

                Class cls = loader.loadClass("com.itap.template."
                        + classFile.getName().substring(0,
                                classFile.getName().lastIndexOf(".")));
                ClassLoader temp = cls.getClassLoader();
            }
        }

        return true;

    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return false;
}

1 个答案:

答案 0 :(得分:1)

当您需要在运行时加载新生成的类时,

URLClassLoader会很有用。不幸的是,您将无法使用URLCLassLoader重新加载已加载类的定义(即重新加载类)。

  

当我使用下面的代码加载新创建的类时,我不是   能够访问注入的方法。我想我无法覆盖   现有的运行时定义。

URLClassLoader将检查指定的类是否已加载。如果找到它,它只返回指向已加载类的实例。因此,您将无法覆盖现有的运行时定义。

<强>解决方案: 要在Java中支持动态类重新加载的标准方法,应该读取类的字节信息(来自其.class文件)并编写自定义类加载器以使用此字节信息加载类。

使用自定义ClassLoader时要记住的要点:

  • 要重新加载一个类,ClassLoader的现有实例(加载该类)和所有已加载的类实例应该被垃圾收集。
  • 自定义ClassLoader必须只加载特定的类(需要加载/重新加载)。请求加载所有其他类(内部Java类或其他包中的类)必须委托给其父类加载器。尝试加载内置系统类可能会导致特权异常。

加载类时类加载器遵循的步骤是:

  1. 检查班级是否已加载。
  2. 如果未加载,请让父类加载器加载该类。
  3. 如果父类加载器无法加载类,请尝试在此类加载器中加载它。
  4. 当你实现一个能够重新加载类的类加载器时,你需要偏离这个序列。 不应将类重新加载请求委托给父类加载器。

    以下示例链接可以帮助您在Java中开发自定义类加载器。 http://www.javablogging.com/java-classloader-2-write-your-own-classloader/
    http://tutorials.jenkov.com/java-reflection/dynamic-class-loading-reloading.html

    在您的评论后编辑:

      

    我认为语句InputStream stream =   。的getClass()getClassLoader()的getResourceAsStream(名称)。的   示例中的loadClassData函数没有拿起最新的   该课程的版本。

    你是对的,它没有拿起最新版本的课程,因为它使用现有的ClassLoader来获取流(指向你班级的旧版本)。

    你可以使用,

    FileInputStream stream = new FileInputStream("Path to your class file");
    ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    int data = stream.read();
    
    while(data != -1){
        buffer.write(data);
        data = stream.read();
    }
    
    stream.close();
    
    byte[] classData = buffer.toByteArray();
    

    读取类的字节信息,并尝试使用您的ClassLoader版本(自定义ClassLoader)加载它。