Java - Custom ClassLoader - пытается загрузить класс, используя полный путь к файлу класса - PullRequest
1 голос
/ 17 августа 2011

Как часть проекта HTTP WebServer для академических целей, я пытаюсь написать свой собственный загрузчик классов для классов веб-приложений, но, похоже, не понимаю, как это правильно.

Вообще говоря, веб-приложениярасположены в своих собственных папках, файл ".class" веб-приложения совпадает с его прямым именем родительской папки.(например, Web1 / Web1.class).Приведенный ниже код работает нормально, пока я не достигну метода defineClass(), а затем выгоняет меня со следующим исключением:

java.io.FileNotFoundException: C:\inetpub\javawwwroot\WebApps\java\lang\Object\.Object.class (The system cannot find the path specified)

Стоит отметить, что C:\inetpub\javawwwroot\WebApps\part равняется переменной m_WebAppsFullPath в приведенном ниже коде.

Кроме того, при попытке использовать

InputStream in = getResourceAsStream(clsFile);

вместо InputStream in = new FileInputStream(clsFile);

Iполучить нулевое возвращаемое значение ...

ОБНОВЛЕНИЕ : Короче говоря, как я могу загрузить определенный класс, который не находится в "CLASSPATH" и не находится ни в одном из пакетовмой проект?

protected synchronized Class loadClass(String className, boolean resolve) 
                             throws ClassNotFoundException 
{
    log("Loading class: " + className + ", resolve: " + resolve);

    // 1. is this class already loaded?
    Class cls = findLoadedClass(className);
    if (cls != null)
    {
        return cls;
    }

    // 2. get class file name from class name
    String classRelativePath = className.replace('.', '/');
    String classFileName = 
        ((className.lastIndexOf('.') != -1) ? className.substring(className.lastIndexOf('.')) : className) + ".class";

    String clsFile = m_WebAppsFullPath + "\\" + classRelativePath + "\\" + classFileName;

    // 3. get bytes for class
    byte[] classBytes = null;
    try 
    {
        //InputStream in = getResourceAsStream(clsFile);
        InputStream in = new FileInputStream(clsFile);
        byte[] buffer = new byte[BUFFER_SIZE];
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int n = -1;
        while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
            out.write(buffer, 0, n);
        }
        classBytes = out.toByteArray();
    }
    catch (IOException e) {
        log("ERROR loading class file: " + e);
    }

    if (classBytes == null) {
        throw new ClassNotFoundException("Cannot load class: " + className);
    }

    // 4. turn the byte array into a Class
    try {
        cls = defineClass(className, classBytes, 0, classBytes.length);
        if (resolve) {
            resolveClass(cls);
        }
    }
    catch (SecurityException e) { 
        // loading core java classes such as java.lang.String
        // is prohibited, throws java.lang.SecurityException.
        // delegate to parent if not allowed to load class
        cls = super.loadClass(className, resolve);
    }

    return cls;
}

Есть идеи, как мне заставить его работать?

Спасибо!

1 Ответ

4 голосов
/ 17 августа 2011

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

Как правило, загрузчики классов в Java связаны друг с другом, что означает, что ваш загрузчик классов был определен другим (скорее всего, системным загрузчиком классов). Поэтому рекомендуется НЕ перезаписывать метод loadClass самостоятельно, а вместо этого перезаписывать два метода findClass (String): Class и loadClassData (String): Class.

Вот выдержка из Javadoc класса Classloader:

Класс ClassLoader использует модель делегирования для поиска классы и ресурсы. Каждый экземпляр ClassLoader имеет связанный родительский загрузчик классов. Когда попросили найти класс или ресурс, экземпляр ClassLoader будет делегировать поиск класса или ресурса в родительский загрузчик классов, прежде чем пытаться найти сам класс или ресурс. Встроенный загрузчик классов виртуальной машины, называется "загрузчик класса начальной загрузки", не имеет родителя, но может служить родителем экземпляра ClassLoader.

В том же Javadoc приведен даже пример того, как правильно определить собственный загрузчик классов:

class NetworkClassLoader extends ClassLoader {
     String host;
     int port;

     public Class findClass(String name) {
         byte[] b = loadClassData(name);
         return defineClass(name, b, 0, b.length);
     }

     private byte[] loadClassData(String name) {
         // load the class data from the connection
          . . .
     }
 }

Я думаю, что вы можете прочитать это: Javadoc для ClassLoader

...