У меня трудные времена с загрузчиками классов Java, возможно, кто-то может пролить свет на это Я раскрыл суть проблемы следующим образом:
Есть три класса - ClassLoaderTest
, LoadedClass
и LoadedClassDep
. Они все на разных путях.
ClassLoaderTest
создает новый URLClassLoader
- myClassLoader
, заполняя его путями к оставшимся двум классам и своим собственным загрузчиком классов (то есть загрузчиком классов приложения) в качестве родительского. Затем он использует Class.forName("com.example.LoadedClass", true, myClassLoader)
для загрузки LoadedClass
через отражение. LoadedClass
импортирует LoadedClassDep
. Если я запускаю выше, используя:
java -cp /path/to/the/ClassLoaderTest ClassLoaderTest "/path/to/LoadedClass" "/path/to/LoadedClassDep"
и используя аргументы командной строки для простого URLClassLoader
все работает нормально. Используя статические инициализаторы, я подтверждаю, что два класса загружены с экземпляром URLClassLoader
.
ОДНАКО, и это проблема, если я сделаю:
java -cp /path/to/the/ClassLoaderTest:/path/to/the/LoadedClass ClassLoaderTest "/path/to/LoadedClassDep"
Не удается загрузить LoadedClassDep (ClassNotFoundException
). LoadedClass
загружен правильно, но с sun.misc.Launcher$AppClassLoader
, а не URLClassLoader
!
Казалось бы, поскольку загрузчик классов приложения способен загружать LoadedClass
, он также пытается загрузить LoadedClassDep
, игнорируя URLClassLoader
.
Вот полный исходный код:
</p>
<code>package example.bc;
public class ClassloaderTest {
public static void main(String[] args) {
new ClassloaderTest().run(args);
}
private void run(String[] args) {
URLClassLoader myClasLoader = initClassLoader(args);
try {
Class<?> cls = Class.forName("com.example.bc.LoadedClass", true, myClasLoader);
Object obj = cls.newInstance();
cls.getMethod("call").invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
private URLClassLoader initClassLoader(String[] args) {
URL[] urls = new URL[args.length];
try {
for (int i = 0; i < args.length; i++) {
urls[i] = new File(args[i]).toURI().toURL();
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return new URLClassLoader(urls, getClass().getClassLoader());
}
}
package com.example.bc;
import com.bc.LoadedClassDep;
public class LoadedClass {
static {
System.out.println("LoadedClass " + LoadedClass.class.getClassLoader().getClass());
}
public void call() {
new LoadedClassDep();
}
}
package com.bc;
public class LoadedClassDep {
static {
System.out.println("LoadedClassDep " + LoadedClassDep.class.getClassLoader().getClass());
}
}
</code>
Надеюсь, я прояснил это достаточно. Моя проблема в том, что я знаю только путь к ClassLoadeTest
во время компиляции, я должен использовать строки во время выполнения для других путей. Итак, есть идеи, как заставить работать второй сценарий?