Загрузка динамического класса Java внутри веб-приложения
Я сделал проект Java, проект только этот класс:
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, и есть класс, расширяющий 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;
}
}
Если я запускаю этот код внутри основного метода, он работает правильно, и когда я пытаюсь запустить его на сервере, возникает проблема при загрузке класса, я получаю ClassNotFoundException (Processor). Я попытался поместить jar в tomcat/lib, project/WEB-INF/lib и ничего не изменилось.
Есть идеи, что я делаю не так?
1 ответ
Я решил не так, как хотел, но решил:
Сначала я попытался загрузить 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;
}
При корректной загрузке класса Process проблема возникает в методе testPlugins, когда он пытается привести к Processor (ClassCastException, не может привести Process к Processor):
public void testPlugins(){
Processor plugin = (Processor) loadJars("C:\\Users\\...\\Desktop\\processor.jar",
"C:\\Users\\...\\Desktop\\plugin.jar",
"test.process.Process");
processor.loadData("dada");
}
Все еще нужно много читать о загрузке классов, но я предполагаю, что проблема в том, что он не распознает процессор, загруженный из C:\Users\...\Desktop\processor.jar, так же, как процессор, загруженный из контекста webapp или он "забывает", процесс расширяет процессор.
Я спешил, поэтому у меня не было времени на исследования, для решения проблемы я использовал методы с помощью рефлексии:
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;
}