Модераторы: LSD, AntonSaburov
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблема с ClassLoader-ом 
:(
    Опции темы
3,14
Дата 3.3.2013, 21:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1614
Регистрация: 18.6.2004
Где: Н. Новгород

Репутация: 6
Всего: 24



Есть у меня некий Launcher, который запускает основное приложение, подгружая его моим же ClassLoader-ом (AppLoader):
Код

public class AppLauncher {
    public static URL [] getJars() throws MalformedURLException {
        return new URL [] {
            new File("e:/MediaCatalog/release/lib/mp3agic-0.7-patch-0.1.jar").toURL(),
            new File("e:/MediaCatalog/release/plugins/mc-audio-0.01.jar").toURL()
        };
    }
    
    public static void invokeMain(ClassLoader loader, String className, String [] args) throws ReflectiveOperationException {
        Class<?> clazz = loader.loadClass(className);
        Method main = clazz.getMethod("main", String [].class);
        main.invoke(null, (Object) args);
    }

    public static void main(String [] args) throws Exception {
        AppLoader loader = null;
        try {
            loader = new AppLoader(getJars(), ClassLoader.getSystemClassLoader());
            invokeMain(loader, "org.mc.main.App", args);
        } finally {
            if (loader != null) {
                loader.close();
            }
        }
    }
}

AppLoader является наследником URLCLassLoader-а, и в конструкторе тупо передает ему аргументы.
Проблема в следующем, приложение запускается, делаем в нем:
App.class.getClassLoader() //подгруженный класс
или
getClass().getClassLoader()
и возвращается системный ClassLoader, а не объявленный мной. Соответственно классы из подключенных Jar-ов он не видит...


--------------------
Может быть, это только мой бред,
Может быть, жизнь не так хороша,
Может быть, я не выйду на свет,
Но я летал, когда пела душа...
PM MAIL   Вверх
jk1
Дата 4.3.2013, 07:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



А Ваш собственный загрузчик выполняет делегацию к родительскому загрузчику? Есть подозрение, что искомый класс уже загружен родительским CLassLoader'ом, потому Ваш собственный и не пытается его грузить сам.  


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
3,14
Дата 4.3.2013, 07:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1614
Регистрация: 18.6.2004
Где: Н. Новгород

Репутация: 6
Всего: 24



Выполняет. А как это обойти? Не уж то добавлять загрузку классов еще?


--------------------
Может быть, это только мой бред,
Может быть, жизнь не так хороша,
Может быть, я не выйду на свет,
Но я летал, когда пела душа...
PM MAIL   Вверх
jk1
Дата 4.3.2013, 09:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Цитата

А как это обойти?


Тут есть два принципиально разных способа:

1. Исключить parent delegation для конкретных классов. Работать скорее всего будет, но это похоже на костыль и чревато jar hell 
2. Понять, почему system classloader ухитрился загрузить целевой класс первым и сделать так, чтобы этого не происходило.

Я бы выбрал второй способ. Если приаттачите побольше исходников я даже смогу указать где именно у Вас проблема.


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
3,14
Дата 4.3.2013, 10:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1614
Регистрация: 18.6.2004
Где: Н. Новгород

Репутация: 6
Всего: 24



Код загрузчика:
Код

public class AppLoader extends URLClassLoader {
    
    public static class DuplicateClassError extends Error {

        /**
         * Generated UID
         */
        private static final long serialVersionUID = 3409679656611039446L;
        
        public DuplicateClassError(String classNameA, String classNameB) {
            super("Different classes with names equals ignore case: " + classNameA + ", " + classNameB);
        }
        
    }
    
    private HashMap<String, Class<?>> cache = new HashMap<String, Class<?>>();
    
    public AppLoader(URL [] urls, ClassLoader parent) throws MalformedURLException {
        super(urls, parent);
    }
    
    public synchronized Class<?> loadClass(String name) throws ClassNotFoundException {
        Class<?> result = cache.get(name.toLowerCase());
        if (result != null) {
            //check if it's not the same classes
            if (!result.getName().equals(name)) {
                throw new DuplicateClassError(result.getName(), name);
            }
            return result;
        }
        //do default load
        result = super.loadClass(name);
        //save to cache
        cache.put(result.getName().toLowerCase(), result);
        return result;
    }
    
    public Class<?> findClass(String name) throws ClassNotFoundException {
     Class<?> result = cache.get(name.toLowerCase());
     if (result == null) {
         result = super.findClass(name);
         cache.put(name.toLowerCase(), result);
     }
     return result;
    }
    
    public Class<?> findLoadedClassIgnoreCase(String name) throws ClassNotFoundException {
        Class<?> result = cache.get(name.toLowerCase());
        if (result == null) {
            throw new ClassNotFoundException ("Class " + name + " is not loaded");
        }
        return result;
    }
}

К другим файлам проекта Launcher и Loader вроде как не обращаются, так что странно, что загрузка класса App идет.


--------------------
Может быть, это только мой бред,
Может быть, жизнь не так хороша,
Может быть, я не выйду на свет,
Но я летал, когда пела душа...
PM MAIL   Вверх
3,14
Дата 6.3.2013, 21:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1614
Регистрация: 18.6.2004
Где: Н. Новгород

Репутация: 6
Всего: 24



Проверил, класс ранее загружен не был, и загружался именно через делегирование при вызове:
Код

    @Override
    public synchronized Class<?> loadClass(String name) throws ClassNotFoundException {
             System.out.printf("[Loading class: %s]\n\n", name);
        Class<?> result = cache.get(name.toLowerCase());
        if (result != null) {
            //check if it's not the same classes
            if (!result.getName().equals(name)) {
                throw new DuplicateClassError(result.getName(), name);
            }
            return result;
        }
        Class<?> clazz = super.findLoadedClass(name);
        if (clazz != null) {
            System.out.printf("[Loading class: %s - is already loaded by %s]\n\n", name, clazz.getClassLoader().getClass().getName());
        }
        //do default load
        result = super.loadClass(name);
        //save to cache
        cache.put(result.getName().toLowerCase(), result);
        return result;
    }

В консоль падало: [Loading class: org.mc.main.App], а вот что класс был ранее загружен нет, не падало, тем не менее, когда после загрузки вызывал тип ClassLoader-а, возвращался совсем не мой ClassLoader, а системный:
Код

        Class<?> clazz = loader.loadClass(className);
        System.out.printf("[App ClassLoader is: %s]\n\n", clazz.getClassLoader().getClass().getName());

В консоль валилось: [App ClassLoader is: sun.misc.Launcher$AppClassLoader] а не org.mc.main.AppLoader


--------------------
Может быть, это только мой бред,
Может быть, жизнь не так хороша,
Может быть, я не выйду на свет,
Но я летал, когда пела душа...
PM MAIL   Вверх
jk1
Дата 7.3.2013, 23:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник
Сообщений: 1168
Регистрация: 17.10.2008
Где: Санкт-Петербург

Репутация: 40
Всего: 75



Раз загружал системный, значит библиотеки оказались в ClassPath. Если их оттуда убрать, то системный загрузить не сможет и мы получим искомое.


--------------------
Opinions are like assholes — everybody has one
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Java"
LSD   AntonSaburov
powerOn   tux
javastic
  • Прежде, чем задать вопрос, прочтите это!
  • Книги по Java собираются здесь.
  • Документация и ресурсы по Java находятся здесь.
  • Используйте теги [code=java][/code] для подсветки кода. Используйтe чекбокс "транслит", если у Вас нет русских шрифтов.
  • Помечайте свой вопрос как решённый, если на него получен ответ. Ссылка "Пометить как решённый" находится над первым постом.
  • Действия модераторов можно обсудить здесь.
  • FAQ раздела лежит здесь.

Если Вам помогли, и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, LSD, AntonSaburov, powerOn, tux, javastic.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Java: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1334 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.