Я использую JBoss 7 (загрузка зависимостей была изменена в этой версии).
Моя военная программа загружается на серверные банки и должна использовать классы внутри них, но она получает ClassNotFoundException
.
Поэтому я не могу найти способ динамического добавления jar-зависимостей в модули - MANIFEST.MF
, jboss-deployment-structure.xml
- статический способ сделать это.
JBoss 7: как динамически загружать банки
Ответ 1
Просто перефразируйте вопрос, чтобы убедиться, что он правильно,
Вы хотите загрузить произвольный файл jar на сервер, а затем использовать содержащиеся в нем классы/ресурсы в JVM? Без перезапуска JVM и/или редактирования вашей конфигурации.
Если это так, то вы должны загрузить jar в загрузчик классов (при необходимости привязав свой текущий загрузчик классов), а затем загрузите класс оттуда.
Предполагая, что вы храните файл jar файла физически на сервере, вы можете, например, сделать что-то вроде:
public static Class<?> loadClass(String className, String jarFileLocation)
throws MalformedURLException, ClassNotFoundException {
URL jarUrl = new File(jarFileLocation).toURI().toURL();
ClassLoader classLoader = new URLClassLoader(new URL[] {jarUrl }, MyClass.class.getClassLoader());
return classLoader.loadClass(className);
}
public static Object executeMethodOndClass(String methodName, Class<?>[] parameterTypes,
Object[] parameters, String className, String jarFileLocation)
throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException,
NoSuchMethodException, InvocationTargetException {
Class<?> loadedClass = loadClass(className, jarFileLocation);
Method method = loadedClass.getMethod(methodName, parameterTypes);
Object instance = loadedClass.newInstance();
return method.invoke(instance, parameters);
}
Ps. это грубый код, я даже не компилировал его или не тестировал; он должен работать, но не более того, и есть шанс, что я что-то забыл или сделал опечатку; -)
Pps. позволяя загружать пользовательские файлы jar, и классы из него, которые должны выполняться, приносят с собой ряд рисков (безопасности).
Ответ 2
@Rage: Этот вопрос в предыдущем потоке stackoverflow может дать вам некоторые сведения о том, как организовать банки: будь то ваши собственные или сторонние банки.
Ответ 3
Попробуйте это (я схватил его где-то в Интернете):
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public final class ClassPathHacker {
private static final Class<?>[] PARAMS = new Class<?>[] { URL.class };
private static final Logger LOG_CPH = LoggerFactory.getLogger(ClassPathHacker.class);
private ClassPathHacker() {}
public static void addFile(final String pFileName) throws IOException {
final File myFile = new File(pFileName);
ClassPathHacker.addFile(myFile);
}
public static void addFile(final File pFile) throws IOException {
ClassPathHacker.addURL(pFile.toURI().toURL());
}
public static void addURL(final URL pFileUrl) throws IOException {
/* variables definition */
final URLClassLoader sysLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
final Class<?> sysClass = URLClassLoader.class;
try {
final Method myMethod = sysClass.getDeclaredMethod("addURL", PARAMS);
myMethod.setAccessible(true);
myMethod.invoke(sysLoader, new Object[] { pFileUrl });
} catch (final Exception exc) {
ClassPathHacker.LOG_CPH.error(exc.getLocalizedMessage(), exc);
throw new IOException(exc.getLocalizedMessage());
}
}
}
Вместе с этим методом:
private static void hackClassPath(final File myData) {
if (myData.isDirectory()) {
/* block variables */
final File[] myList = myData.listFiles();
/* hacking classpath... */
for (final File tmp : myList) {
try {
ClassPathHacker.addFile(tmp.getAbsolutePath());
MainApplication.MAIN_LOG.trace("{} added to classpath",
tmp.getAbsolutePath());
} catch (final IOException iOE) {
MainApplication.MAIN_LOG.error(iOE.getLocalizedMessage(),
iOE);
}
}
}
}
И с этим образцом вызова:
MainApplication.hackClassPath(new File("test/data"));
MainApplication.hackClassPath(new File("data"));
Немного взломанный, но, возможно, он работает... это среда выполнения добавляет все JAr файлы, доступные в каталоге данных или test/data, к запущенному пути к классам.