2014-11-29 1 views
3

Я написал загрузчик классов Java для загрузки классов из файла jar.Как загрузить классы из файла jar в правильном порядке

Enumeration<JarEntry> entries = jarFile.entries(); 
    while (entries.hasMoreElements()) { 
     JarEntry element = entries.nextElement(); 
     if (element.getName().endsWith(".class")) { 
       //Class Manipulation via ASM 
       //Loading class with MyClassloader 
     } 
    } 

Проблема заключается в том: Когда я загружаю класс, который Sublcass из класса в том же Jar и подкласс не загружен, я получаю ClassNotFoundException.

Пример:

class A extends B{} 
Class B{} 

Из алфавитного порядка, класс A загружен в первую очередь. Я получаю исключение ClassNotFoundException для класса B. В это время класс B не загружается.

+0

Показать код закомментирована, который, когда фактический вопрос , (Если, конечно, ваш класс 'B' не указан или иным образом не включен в путь класса поиска.) – chrylis

ответ

3

Я предполагаю, что загрузка вашего класса выполняется как некоторая нажатием файлов классов. Вы должны скорее тянуть их. Для того, чтобы объяснить, что я имею в виду, давайте рассмотрим краткий пример нормального класса Java загрузка:

class Main { 
    public static void main(String[] args) { 
    new B(); 
    } 
} 
class B extends A { } 
class A { } 

При создании new B(), класс загрузчик Main в основном выполняет classLoader.loadClass("B"). На данный момент суперкласс класса BA еще не загружен. В то же время загрузчик классов не может знать, что B имеет A в качестве своего суперкласса. Таким образом, загрузчик классов берет на себя ответственность за загрузку класса, прося себя classLoader.loadClass("A") до завершения загрузки класса B.

Предположим, что загрузчик классов не знал ни о A или B, но это был метод явно загружать классы это получает от внешнего объекта с classLoader.inject(String, byte[]). Эта последовательность вызова будет затем не вычислить:

classLoader.inject("B", bBytes); 
classLoader.inject("A", aBytes); 

, потому что при загрузке B, класс заряжающий не знает о A.

Что вам нужно сделать при внедрении свой собственный загрузчик классов для хранения классов в какой-то карте и реализовать метод класса загрузки что-то загрузчик класса как:

protected Class<?> findClass(String name) throws ClassNotFoundException { 
    byte[] bytes = map.get(name); 
    if (bytes != null) { 
    return defineClass(name, bytes, 0, bytes.length); 
    } else { 
    throw new ClassNotFoundException(name); 
    } 
} 

Позволяя загрузчик классов в определите порядок загрузки, вы полностью избегаете этой проблемы.

Чтобы быть еще более точным, что вам нужно сделать манипуляции и загрузки в два этапа, где алгоритм псевдо будет выглядеть примерно так:

Enumeration<JarEntry> entries = jarFile.entries(); 
MyClassLoader classLoader = new MyClassLoader(); 
// First we generate ALL classes that the class loader is supposed to load. 
// We then make these classes accessible to the class loader. 
while (entries.hasMoreElements()) { 
    JarEntry element = entries.nextElement(); 
    if (element.getName().endsWith(".class")) { 
    // Class Manipulation via ASM 
    classLoader.addClass(...); 
    } 
} 
// Now that the class loader knows about all classes that are to be loaded 
// we trigger the loading process. That way, the class loader can query 
// itself about ANY class that it should know. 
while (entries.hasMoreElements()) { 
    JarEntry element = entries.nextElement(); 
    if (element.getName().endsWith(".class")) { 
    classLoader.loadClass(...); 
    } 
} 
+0

Да, так вы бы реализовали его внутренне. Тем не менее, вы никогда не должны выставлять класс определения снаружи. –

+0

Извините, я удалил комментарий раньше. Моя проблема в том, что я не получаю ту часть, которую определяет classloader, этот класс B должен быть загружен до класса A, если класс A расширяет B {}. – Mathias

+0

Это внутренняя виртуальная машина. Если реализуется загрузчик классов, ему необходимо загрузить другой класс перед загрузкой текущего класса, он приостанавливает загрузку текущего класса и ** сам запрос ** для следующего класса. Вот почему все соответствующие классы должны быть известны из загрузчика классов перед загрузкой первого класса.Установите точку останова в методе класса нагрузки, и вы поймете, что происходит. –