Java 动态 Class 在 webapp 中加载
Java Dynammic Class loading inside webapp
我做了一个java项目,项目只包含这个class:
package test.processor;
public abstract class Processor {
public abstract void loadData(String objectId);
public abstract void processData();
public abstract void saveData(String objectId);
}
项目导出为 jar 文件(processor.jar)
然后我做了另一个导入 processor.jar 的项目,并且有一个 class 扩展了 Processor:
package test.process;
import test.processor.Processor;
public class Process extends Processor{
@Override
public void loadData(String objectId) {
System.out.println("LOAD DATAAAAAAAAAAAA");
}
@Override
public void processData() {
System.out.println("PROCESS DATAAAAAAAAAAAA");
}
@Override
public void saveData(String objectId) {
System.out.println("SAVE DATAAAAAAAAAAAA");
}
}
该项目也导出为 jar (plugin.jar)。
最后,我编写了一些代码来动态加载插件:
import test.processor.Processor;
public class Test {
public void testPlugins(){
Processor plugin = (Processor) loadJar(
"C:\Users\...\Desktop\plugin.jar",
"test.process.Process");
processor.loadData("dada");
}
private Object loadJar(String jar, String className){
File jarFile = new File(jar);
Object instance = null;
try {
URL jarpath = jarFile.toURI().toURL();
String jarUrl = "jar:" + jarpath + "!/";
URL urls[] = { new URL(jarUrl) };
URLClassLoader child = new URLClassLoader(urls);
Class classToLoad = Class.forName(nomeClasse, true, child);
instance = classToLoad.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}
return instance;
}
}
如果我 运行 main 方法中的代码它工作正常,一旦我尝试 运行 它在服务器中加载 class 时出现问题,我得到ClassNotFoundException(处理器)。
我尝试将罐子放入 tomcat/lib、project/WEB-INF/lib,但没有任何变化。
知道我做错了什么吗?
我没有按我想要的方式解决,但是我解决了:
首先,我尝试手动加载 process.jar:
private Object loadJars(String processJar, String pluginJar, String className){
File processJarFile = new File(processJar);
File pluginJarFile = new File(pluginJar);
Object instance = null;
try {
URL processJarPath = processJarFile.toURI().toURL();
String processJarUrl = "jar:" + processJarPath + "!/";
URL pluginJarPath = pluginJarFile.toURI().toURL();
String pluginJarUrl = "jar:" + pluginJarPath + "!/";
URL urls[] = { new URL(processJarUrl), new URL(pluginJarUrl) };
URLClassLoader child = new URLClassLoader(urls);
Class classToLoad = Class.forName(nomeClasse, true, child);
instance = classToLoad.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}
return instance;
}
正确加载进程 class,问题发生在 testPlugins 方法中,一旦它尝试转换为处理器(ClassCastException,无法将进程转换为处理器):
public void testPlugins(){
Processor plugin = (Processor) loadJars("C:\Users\...\Desktop\processor.jar",
"C:\Users\...\Desktop\plugin.jar",
"test.process.Process");
processor.loadData("dada");
}
仍然需要阅读很多关于 classloading 的内容,但我想问题是它无法识别从 C:\Users\...\Desktop\processor.jar 加载的处理器与从 webapp 上下文加载的处理器相同,或者它 "forgets" Process extends Processor.
赶时间没时间研究,为了解决问题我用反射调用了方法:
public void modifiedTestPlugins(){
Object plugin = loadJar("C:\Users\...\Desktop\processor.jar",
"C:\Users\...\Desktop\plugin.jar",
"test.process.Process");
try {
Method processData = findMethod(obj.getClass(), "processData");
//here I invoke the processData method, it prints: PROCESS DATAAAAAAAAAAAA
loadData.invoke(processData, new Object[]{});
} catch (Exception e) {
e.printStackTrace();
}
}
private static Method findMethod(Class clazz, String methodName) throws Exception {
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName))
return methods[i];
}
return null;
}
我做了一个java项目,项目只包含这个class:
package test.processor;
public abstract class Processor {
public abstract void loadData(String objectId);
public abstract void processData();
public abstract void saveData(String objectId);
}
项目导出为 jar 文件(processor.jar)
然后我做了另一个导入 processor.jar 的项目,并且有一个 class 扩展了 Processor:
package test.process;
import test.processor.Processor;
public class Process extends Processor{
@Override
public void loadData(String objectId) {
System.out.println("LOAD DATAAAAAAAAAAAA");
}
@Override
public void processData() {
System.out.println("PROCESS DATAAAAAAAAAAAA");
}
@Override
public void saveData(String objectId) {
System.out.println("SAVE DATAAAAAAAAAAAA");
}
}
该项目也导出为 jar (plugin.jar)。
最后,我编写了一些代码来动态加载插件:
import test.processor.Processor;
public class Test {
public void testPlugins(){
Processor plugin = (Processor) loadJar(
"C:\Users\...\Desktop\plugin.jar",
"test.process.Process");
processor.loadData("dada");
}
private Object loadJar(String jar, String className){
File jarFile = new File(jar);
Object instance = null;
try {
URL jarpath = jarFile.toURI().toURL();
String jarUrl = "jar:" + jarpath + "!/";
URL urls[] = { new URL(jarUrl) };
URLClassLoader child = new URLClassLoader(urls);
Class classToLoad = Class.forName(nomeClasse, true, child);
instance = classToLoad.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}
return instance;
}
}
如果我 运行 main 方法中的代码它工作正常,一旦我尝试 运行 它在服务器中加载 class 时出现问题,我得到ClassNotFoundException(处理器)。 我尝试将罐子放入 tomcat/lib、project/WEB-INF/lib,但没有任何变化。
知道我做错了什么吗?
我没有按我想要的方式解决,但是我解决了:
首先,我尝试手动加载 process.jar:
private Object loadJars(String processJar, String pluginJar, String className){
File processJarFile = new File(processJar);
File pluginJarFile = new File(pluginJar);
Object instance = null;
try {
URL processJarPath = processJarFile.toURI().toURL();
String processJarUrl = "jar:" + processJarPath + "!/";
URL pluginJarPath = pluginJarFile.toURI().toURL();
String pluginJarUrl = "jar:" + pluginJarPath + "!/";
URL urls[] = { new URL(processJarUrl), new URL(pluginJarUrl) };
URLClassLoader child = new URLClassLoader(urls);
Class classToLoad = Class.forName(nomeClasse, true, child);
instance = classToLoad.newInstance();
} catch (Exception ex) {
ex.printStackTrace();
}
return instance;
}
正确加载进程 class,问题发生在 testPlugins 方法中,一旦它尝试转换为处理器(ClassCastException,无法将进程转换为处理器):
public void testPlugins(){
Processor plugin = (Processor) loadJars("C:\Users\...\Desktop\processor.jar",
"C:\Users\...\Desktop\plugin.jar",
"test.process.Process");
processor.loadData("dada");
}
仍然需要阅读很多关于 classloading 的内容,但我想问题是它无法识别从 C:\Users\...\Desktop\processor.jar 加载的处理器与从 webapp 上下文加载的处理器相同,或者它 "forgets" Process extends Processor.
赶时间没时间研究,为了解决问题我用反射调用了方法:
public void modifiedTestPlugins(){
Object plugin = loadJar("C:\Users\...\Desktop\processor.jar",
"C:\Users\...\Desktop\plugin.jar",
"test.process.Process");
try {
Method processData = findMethod(obj.getClass(), "processData");
//here I invoke the processData method, it prints: PROCESS DATAAAAAAAAAAAA
loadData.invoke(processData, new Object[]{});
} catch (Exception e) {
e.printStackTrace();
}
}
private static Method findMethod(Class clazz, String methodName) throws Exception {
Method[] methods = clazz.getMethods();
for (int i = 0; i < methods.length; i++) {
if (methods[i].getName().equals(methodName))
return methods[i];
}
return null;
}