В первую очередь, это - Java 1.4 (ограничения проекта). Я пытаюсь создать администратор приложений. Это загружает основной класс каждого приложения с помощью своего собственного экземпляра пользовательского classloader. После этого это создает экземпляр основного класса с помощью отражения. Каждое приложение реализует единый интерфейс поэтому после того, как экземпляр создается, это выполняет предопределенный метод приложения.
Однако я испытываю некоторые затруднения в ТОЧКЕ КАТАСТРОФИЧЕСКОГО ОТКАЗА 1 (см. код). Класс не распознан как одна реализация, он - интерфейс. Если я комментирую этот блок кода, я получаю ClassCastException в ТОЧКЕ КАТАСТРОФИЧЕСКОГО ОТКАЗА 2.
Я предполагаю, что обе ошибки связаны с той же проблемой (конечно).
Кто-либо может помочь мне? Соответствующая часть кода следует (импорт удален)...
Большое спасибо.
Marcus
//AppManager.java
public class AppManager {
public ThreadGroup threadGroup;
private Class appClass;
private AppInstance appInst;
public AppContextImpl context;
private AppManager(CustomClassLoader cl, String mainClass) throws ClassNotFoundException {
final String className = mainClass;
final CustomClassLoader finalLoader = cl;
appClass = cl.loadClass(mainClass);
// DEBUG CODE:
Class[] k1 = AppInstance.class.getInterfaces();
System.out.println(k1.length + " interfaces for AppInstance.class:");
for (int ii = 0; ii < k1.length; ii++) {
System.out.println(" " + ii + " - " + k1[ii].getName() + " (" + k1[ii].getClassLoader() + ")");
}
Class[] k2 = appClass.getInterfaces();
System.out.println(k2.length + " interfaces for appClass instance:");
for (int ii = 0; ii < k2.length; ii++) {
System.out.println(" " + ii + " - " + k2[ii].getName() + " (" + k2[ii].getClassLoader() + ")");
}
// CRASH POINT 1
if (!(AppInstance.class.isAssignableFrom(appClass))) {
throw new IllegalArgumentException("Attempt to run a non-AppInstance class: " + appClass);
}
context = new AppContextImpl(mainClass, this);
cl.setAppManager(this);
Constructor m;
try {
m = appClass.getConstructor(new Class[0]);
// CRASH POINT 2
appInst = (AppInstance) m.newInstance(new Object[0]);
appInst.init(context);
} catch (Exception e) {
System.out.println("Got ClassCastException here!\n");
e.printStackTrace();
}
}
public static void main(String[] args) {
App app1;
String path1 = "/home/user/workspace/MultiTaskTest/bin/";
String app1Name = "App1";
Vector v1 = new Vector();
try {
v1.add(new URL(path1));
} catch (MalformedURLException e1) {
final File file1 = new File(path1);
try {
URL path1aux = (URL) AccessController.doPrivileged(
new PrivilegedExceptionAction() {
public Object run() throws IOException {
if (!file1.exists()) {
System.out.println("Warning: \"" + file1.getPath() + "\" not found");
return null;
}
return file1.toURI().toURL();
}
});
if (path1aux != null) {
v1.add(path1aux);
}
} catch (PrivilegedActionException e) {
e.getException().printStackTrace();
}
}
final URL[] array1 = (URL[]) v1.toArray(new URL[v1.size()]);
CustomClassLoader cl1 = (CustomClassLoader) AccessController.doPrivileged(
new PrivilegedAction() { public Object run() {
return new CustomClassLoader(array1);
}});
System.out.println("ClassLoader 1 created: " + cl1);
try {
app1 = new App(cl1, app1Name);
} catch (ClassNotFoundException e) {
e.printStackTrace();
System.out.println("Cannot find class App1.");
}
}
}
//AppInstance.java
public interface AppInstance {
public void init(ContextImpl context);
}
//App1.java
public class App1 implements AppInstance {
private AppContextImpl contextObj;
public void init(AppContextImpl context) {
this.contextObj = context;
System.out.println("Running App1...");
}
}
//AppContextImpl.java
public class AppContextImpl {
public String mainClass;
public AppManager app;
public AppContextImpl(String mainClass, AppManager app) {
this.mainClass = mainClass;
this.app = app;
}
}
//CustomClassLoader.java
public class CustomClassLoader extends URLClassLoader {
AppManager appInst;
public CustomClassLoader(URL[] paths) { super(paths, null); }
public void setAppManager(AppManager app) { this.appInst = app; }
}
Вывод для кода Отладки в файле AppManager.java:
0 interfaces for AppInstance.class:
1 interfaces for appClass instance:
0 - AppInstance (CustomClassLoader@480457)
Ваш класс AppInstance, вероятно, загружается отдельно каждым пользовательским загрузчиком классов. Поскольку объекты класса зависят от фактического класса И от загрузчика классов, это действительно разные классы. Итак, AppInstance из загрузчика классов 1 не то же самое, что AppInstance из загрузчика классов 2.
Что вам нужно сделать, так это использовать стандартную иерархию загрузчика классов: использовать корневой загрузчик классов для вашего приложения и убедиться, что AppInstance загружается загрузчиком классов. Затем сделайте свой собственный загрузчик классов дочерними элементами из корня. Всякий раз, когда им нужен доступ к классу AppInstance, они будут использовать то, что загружено из корня.
Итак, вместо этого:
public CustomClassLoader(URL[] paths) { super(paths, null); }
Вам нужно указать родительский элемент для вашего CustomClassLoader