我正在尝试使用Class.forName在运行时从文件系统上的.jar文件动态加载一个类。我尝试加载的类在另一个.jar文件中实现了一个接口,所以我使用自己的URLClassLoader来引用两个.jars。
代码在不在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());
}
关于为什么这个代码在一个程序而不是另一个程序中工作的任何建议将不胜感激。
非常感谢, 丹
答案 0 :(得分:2)
简短回答而不涉及太多毛茸茸的细节:gameJar和gameDependenciesJar中的一个或两个可能包含IMyClass类/接口的定义。使用子类加载器时的经验法则是子类加载器应该不包含任何“共享”类 - 这些类应仅存在于父类加载器中。
部分解释:Web应用程序类加载器通常具有与普通类加载器不同的委派策略。通常他们更喜欢孩子的班级和父母的班级。普通的类加载器通常更喜欢父类的子类。在您的Web应用程序中,您最终会得到两个独立的IMyClass类定义(父类加载器中的一个def,子项中的一个)。在您的普通应用程序中,子类加载器中的IMyClass定义被忽略,因此只加载了一个定义(在父类加载器中),并且一切都很满意。
答案 1 :(得分: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
的完整声明性名称,而不是仅在MyClass
中调用Class.forName()
。
E.g。
Class clazz = Class.forName("com.xxxx.yyy.MyClass", true, cl);