Java - 自定义类加载器 - 尝试使用类文件完整路径加载类

Mik*_* S. 1 java web-applications classloader

作为用于学术目的的 HTTP WebServer 项目的一部分,我正在尝试为 Web 应用程序类编写自己的自定义类加载器,但似乎无法正确完成。

一般来说,Web 应用程序位于它们自己的文件夹中,Web 应用程序的“.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\部分等于m_WebAppsFullPath变量。

此外,当尝试使用

InputStream in = getResourceAsStream(clsFile);

代替 InputStream in = new FileInputStream(clsFile);

我得到一个空返回值...

更新:简而言之,如何加载既不在“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;
}
Run Code Online (Sandbox Code Playgroud)

知道如何让它工作吗?

谢谢!

小智 5

目前,您不仅要尝试通过自己的类加载器加载自定义类,还要尝试加载它们所依赖的所有系统类。比如java.lang.Object,这是你的问题。

通常,Java 中的类加载器是链式的,这意味着您的类加载器已由另一个类加载器(很可能是系统类加载器)定义。因此,建议不要自己覆盖loadClass 方法,而是覆盖两个方法'findClass(String):Class 和loadClassData(String):Class。

以下是 Classloader 类的 Javadoc 的摘录:

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
          . . .
     }
 }
Run Code Online (Sandbox Code Playgroud)

我想你可能想阅读:Javadoc for ClassLoader