Задачи и первоначальное расследование
Я пытаюсь настроить два экземпляра Oracle Coherence рядом с кешем в одном приложении Java Swing. Идею решения можно найти здесь. Мой случай немного сложнее, и здесь начинается игра.
Краткое описание
В моем случае есть служба учетных записей. Он может иметь две конечные точки: SIT и UAT. Чтобы создать два таких сервиса, мне нужно загрузить два «экземпляра» Coherence, чтобы переопределить конечные точки системными переменными (tangosol.coherence.cacheconfig).
У меня есть:
- основной код приложения находится в файле mainapp.jar;
- интерфейс AccountService, расположенный в файле account-interfaces.jar;
- класс AccountServiceImpl, расположенный в файле account-impl.jar и реализующий интерфейс AccountService;
- мое основное приложение имеет следующую структуру
bin: startup.bat, startup.sh conf: app.properties lib: mainapp.jar, account-interfaces.jar, account-impl.jar, coherence.jar
Подход попробовал
Я создал выделенный дочерний classLoader - InverseClassLoader и сделал AppLaunchClassLoader (по умолчанию Thread.currentThread().GetContextClassLoader() classLoader) его родителем. С помощью InverseClassLoader я загружаю класс AccountServiceImpl:
Class<AccountServiceImpl> acImplClass = contextClassLoader.selfLoad(AccountServiceImpl.class).loadClass(AccountServiceImpl.class);
Constructor<AccountServiceImpl> acConstructor =
acImplClass .getConstructor(String.class);
AccountService acService = acConstructor .newInstance(serviceURL);
Проблемы и вопросы
- Я получаю, что «AccountServiceImpl не может быть приведен к исключениям AccountService», что означает, что эти два класса загружаются разными загрузчиками классов. Но эти загрузчики классов находятся в отношениях родитель-потомок. Итак, я прав, что даже если класс загружается родителем (интерфейс - «абстрактный» тип), его нельзя использовать с классом (конкретным внедрением), загруженным дочерним загрузчиком классов? Зачем тогда нам нужны эти отношения родитель-потомок?
- Я указал интерфейс AccountService в коде, и он был загружен загрузчиком классов по умолчанию. Я попытался обернуть приведенный выше код потоком и установить InverseClassLoader в контекстный загрузчик классов. Ничего не изменилось. Итак, я прав, что я не могу использовать такое кодирование реализации интерфейса (как обычное кодирование) и мне нужно все время использовать отражение для постоянного вызова конкретных методов? (Надеюсь есть решение) ;
- Скажем, я перечислил классы AccountService и AccountServiceImpl для загрузки с помощью InverseClassLoader. Что, если мне нужно, чтобы другие классы, доступные этим двум, также загружались с помощью InverseClassLoader? Есть ли способ сказать, что все «связанные» классы должны быть загружены одним и тем же загрузчиком классов?
Обновлять
Вот InverseClassLoader:
public class InvertedClassLoader extends URLClassLoader {
private final Set<String> classesToNotDelegate = new HashSet<>();
public InvertedClassLoader(URL... urls) {
super(urls, Thread.currentThread().getContextClassLoader());
}
public InvertedClassLoader selfLoad(Class<?> classToNotDelegate) {
classesToNotDelegate.add(classToNotDelegate.getName());
return this;
}
@Override
public Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
if (shouldNotDelegate(className)) {
System.out.println("CHILD LOADER: " + className);
Class<?> clazz = findClass(className);
if (resolve) {
resolveClass(clazz);
}
return clazz;
}
else {
System.out.println("PARENT LOADER: " + className);
return super.loadClass(className, resolve);
}
}
public <T> Class<T> loadClass(Class<? extends T> classToLoad) throws ClassNotFoundException {
final Class<?> clazz = loadClass(classToLoad.getName());
@SuppressWarnings("unchecked")
final Class<T> castedClass = (Class<T>) clazz;
return castedClass;
}
private boolean shouldNotDelegate(String className) {
if (classesToNotDelegate.contains(className) || className.contains("tangosol") ) {
return true;
}
return false;
}