Java ClassLoader - 强制重新加载已加载的类

时间:2018-01-26 10:17:06

标签: java classloader urlclassloader

我目前正在尝试将类加载到我的应用程序中,以便我可以过滤掉那些不包含任何test / @Test方法的类。我希望之后在我的应用程序中运行这些测试。

到目前为止,非常好 - 除了URLClassLoader我使用(或可能是任何ClassLoader)似乎没有实际上重新加载课程位于我的应用程序类路径上。

更准确地说,我的应用程序的用户首先选择了多个.java源文件。然后将它们复制到临时位置,并将许多正则表达式匹配/替换对应用于原始源文件的副本。接下来,编译副本,然后我想将这些已编译的.class - 文件加载到我的应用程序中,以便我可以将它们作为测试运行。
在大多数情况下,这可以按预期工作。

不幸的是,如果任何所选文件的完全限定类名(FQCN)与作为此应用程序一部分的类的FQCN相同(例如此应用程序的测试),ClassLoader将忽略指定的路径(到%temp%\myfolder\)和位于那里的类文件的(更新的)版本,而是使用已经存在/已加载的类版本。

经过一些研究,根据docs(强调我的),可以预期这种行为:

  

•ClassLoader中的loadClass方法在调用加载类时按顺序执行这些任务:
   - 如果某个类已经加载,则返回它。
   - 否则,它会将对新类的搜索委托给父类加载器    - 如果父类加载器没有找到该类,则loadClass调用方法findClass来查找并加载该类。

我尝试使用findClass,但遗憾的是不可见。

因此我的问题 - 有没有人知道如何强制java / ClassLoader从指定路径实际加载类,忽略任何 - FQCN明智 - 相同的现有类?

1 个答案:

答案 0 :(得分:3)

类加载器首先委托其父类加载器,它是如何确定"如果类已经加载"。如果要强制类加载器加载新类,一种方法是在链中插入另一个类加载器,无法加载/查找同一个类。非常快速,不完整的例子:

class FirewallLoader extends ClassLoader {
    public FirewallLoader(ClassLoader parent) {
        super(parent);
    }
    public loadClass(String name, boolean resolve) {
        if (name.equals("some.class.Xyz")) {
            throw ClassNotFoundException();
        }
        super.loadClass(name, resolve);
    }
}

你制作" FirewallLoader"父级或URLClassLoader,然后您的URLClassLoader将加载防火墙加载器过滤掉的任何类的新版本。