在 JAVA 的 运行 时间从 WAR 外部的 JAR 文件动态加载 类 时发生 ClassCastException 错误?
ClassCastException Error while dynamically loading classes from a JAR file outside WAR at run time in JAVA?
我想在我的 war 代码中动态加载 jar 文件(及其 classes)。
为此,我编写了我的对象工厂 class:
import java.io.File;
import java.net.*;
public class ObjectFactory {
private ClassLoader cl;
public ObjectFactory(String jarFilePath) {
try {
File file= new File(jarFilePath);
URL url = file.toURL();
URL[] urls = new URL[]{url};
cl = new URLClassLoader(urls);
} catch (Exception e) {
e.printStackTrace();
}
}
public <T> T getObject(String id){
try {
Class cls = cl.loadClass(id);
T object =(T)cls.newInstance();
return object;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
我有一个 Duck 界面:
public interface Duck {
public String quack(String arg);
}
并且我创建了服务 class 以在运行时获取我想要的 Ducks:
public class DuckServiceClass {
public static Duck getDuck(){
try {
String jarFilePath="\path\to\my\external_jar.jar"
ObjectFactory of = new ObjectFactory(jarFilePath);
Duck d1=of.getObject("implementationOfDuck.RobotDuck");
return d1;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
我的 jar 有一个 Duck 接口的副本,并且有 Duck 的各种实现:
例如 RobotDuck class:
package implementationOfDuck;
import Duck;
public class RobotDuck implements Duck {
@Override
public String quack(String arg) {
return "Q U A N C K!!!" +arg;
}
}
此服务 class 在主要方法中工作正常:
public class WebAppTest {
public static void main(String[] args) {
Duck d1 =DuckServiceClass.getDuck();
System.out.println(d1.getName()+">"+d1.quack("Hello"));
}
}
但是如果我在我的 jsp 页面中引用这个 ServiceClass 方法,它会给我:
java.lang.ClassCastException: implementationOfDuck.RobotDuck cannot be cast to Duck
我的 JSP 页面是:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ page import="Duck" %>
<%@ page import="DuckServiceClass" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Duck-O-Gram</title>
</head>
<body>
<%
Duck d1=DuckServiceClass.getDuck();
%>
<h1><%=d1.quack("Hello")%></h1>
</body>
</html>
任何人都可以指导我如何在网络应用程序中解决这个问题吗?
正如@JimGarrison 所说,Duck
由 webapp class 加载程序和 URLClassLoader
加载两次。
在 URLClassLoader
的构造函数中指定父 class 加载程序可以解决此问题。 cl
将首先使用父 class 加载程序搜索 class/resource,然后从给定的 URL 加载 class/resource。由于 Duck
已经被 webapp class loader 加载,external_jar.jar 中的 Duck.class
将不会再次加载。
public ObjectFactory(String jarFilePath) {
try {
File file= new File(jarFilePath);
URL url = file.toURL();
URL[] urls = new URL[]{url};
cl = new URLClassLoader(urls, getClass().getClassLoader());
} catch (Exception e) {
e.printStackTrace();
}
}
我想在我的 war 代码中动态加载 jar 文件(及其 classes)。
为此,我编写了我的对象工厂 class:
import java.io.File;
import java.net.*;
public class ObjectFactory {
private ClassLoader cl;
public ObjectFactory(String jarFilePath) {
try {
File file= new File(jarFilePath);
URL url = file.toURL();
URL[] urls = new URL[]{url};
cl = new URLClassLoader(urls);
} catch (Exception e) {
e.printStackTrace();
}
}
public <T> T getObject(String id){
try {
Class cls = cl.loadClass(id);
T object =(T)cls.newInstance();
return object;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
我有一个 Duck 界面:
public interface Duck {
public String quack(String arg);
}
并且我创建了服务 class 以在运行时获取我想要的 Ducks:
public class DuckServiceClass {
public static Duck getDuck(){
try {
String jarFilePath="\path\to\my\external_jar.jar"
ObjectFactory of = new ObjectFactory(jarFilePath);
Duck d1=of.getObject("implementationOfDuck.RobotDuck");
return d1;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
我的 jar 有一个 Duck 接口的副本,并且有 Duck 的各种实现: 例如 RobotDuck class:
package implementationOfDuck;
import Duck;
public class RobotDuck implements Duck {
@Override
public String quack(String arg) {
return "Q U A N C K!!!" +arg;
}
}
此服务 class 在主要方法中工作正常:
public class WebAppTest {
public static void main(String[] args) {
Duck d1 =DuckServiceClass.getDuck();
System.out.println(d1.getName()+">"+d1.quack("Hello"));
}
}
但是如果我在我的 jsp 页面中引用这个 ServiceClass 方法,它会给我:
java.lang.ClassCastException: implementationOfDuck.RobotDuck cannot be cast to Duck
我的 JSP 页面是:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ page import="Duck" %>
<%@ page import="DuckServiceClass" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Duck-O-Gram</title>
</head>
<body>
<%
Duck d1=DuckServiceClass.getDuck();
%>
<h1><%=d1.quack("Hello")%></h1>
</body>
</html>
任何人都可以指导我如何在网络应用程序中解决这个问题吗?
正如@JimGarrison 所说,Duck
由 webapp class 加载程序和 URLClassLoader
加载两次。
在 URLClassLoader
的构造函数中指定父 class 加载程序可以解决此问题。 cl
将首先使用父 class 加载程序搜索 class/resource,然后从给定的 URL 加载 class/resource。由于 Duck
已经被 webapp class loader 加载,external_jar.jar 中的 Duck.class
将不会再次加载。
public ObjectFactory(String jarFilePath) {
try {
File file= new File(jarFilePath);
URL url = file.toURL();
URL[] urls = new URL[]{url};
cl = new URLClassLoader(urls, getClass().getClassLoader());
} catch (Exception e) {
e.printStackTrace();
}
}