2

我正在尝试使用 Class.forName 在运行时从文件系统上的 .jar 文件动态加载类。我尝试加载的类在另一个 .jar 文件中实现了一个接口,因此我使用自己的 URLClassLoader 来引用这两个 .jar。

该代码在不在 Web 应用程序的上下文中调用时有效(我已经通过将方法复制并粘贴到单独的程序中并从 main 调用它来测试它)。但是,当我运行/调试 Web 应用程序(我正在使用 NetBeans)时,代码会失败。当我尝试将实例强制转换为 jar_file_dependencies.jar 中指定的接口时,newInstance 方法会引发 ClassCastException。

如果有帮助,这里是相关代码:

       File gameJar = new File("C:\\file_path\\jar_file.jar");

       File gameDependenciesJar = new File("C:\\file_path\\jar_file_dependencies.jar");

        URLClassLoader cl = new URLClassLoader(new URL[]
                {
                    gameJar.toURI().toURL(),
                    gameDependenciesJar.toURI().toURL()
                });

        Class clazz = Class.forName("MyClass", true, cl);

        IMyClass myClass = (IMyClass)clazz.newInstance();

        System.out.println(game);

    } catch (Exception e)
    {
        System.out.println(e.getMessage());
    }

关于为什么此代码在一个程序中而不是另一个程序中工作的任何建议将不胜感激。

非常感谢,丹

4

2 回答 2

2

简短的回答,不涉及太多毛茸茸的细节:gameJar 和 gameDependenciesJar 之一或两者可能包含 IMyClass 类/接口的定义。使用子类加载器时的经验法则是子类加载器不应该包含任何“共享”类——这些应该只存在于父类加载器中。

部分解释:Web 应用程序类加载器通常具有与普通类加载器不同的委托策略。通常他们更喜欢孩子的班级而不是父母的班级。普通类加载器通常更喜欢父类而不是子类。在您的 Web 应用程序中,您最终得到了 IMyClass 类的 2 个单独定义(父类加载器中的一个定义,子类中的一个定义)。在您的普通应用程序中,子类加载器中的 IMyClass 定义被忽略,因此只有一个定义被加载(在父类加载器中),一切都很愉快。

于 2010-12-09T20:30:23.650 回答
0

也许这会有所帮助,(未经测试)

ClassLoader clsLoader = Thread.currentThread().getContextClassLoader();
if (clsLoader == null) {
    clsLoader = this.getClass().getClassLoader();
}

URLClassLoader cl = new URLClassLoader(new URL[]
                {
                    gameJar.toURI().toURL(),
                    gameDependenciesJar.toURI().toURL()
                }, clsLoader);

此外,您应该传递类的完整声明性名称,MyClass而不是仅仅MyClassClass.forName().

例如

Class clazz = Class.forName("com.xxxx.yyy.MyClass", true, cl);
于 2010-12-09T20:42:43.093 回答