【问题标题】:How to set my ClassLoader as the JVM's ClassLoader for loading ALL classes (jar classes included)?如何将我的 ClassLoader 设置为 JVM 的 ClassLoader 以加载所有类(包括 jar 类)?
【发布时间】:2012-04-29 03:18:36
【问题描述】:

我正在编写一个游戏引擎,我需要在其中分析程序中提到的每一个类。由于这是一个游戏引擎,它会以 JAR 文件的形式附加到客户的项目中。从该 JAR 文件中,我需要能够扫描客户端正在使用的每个类。

所以我想我应该创建一个自定义的 ClassLoader!通过重写 ClassLoader,我可以查看加载时正在使用的每个类。

我开始使用 ClassLoaders。这是我所做的: (我从 JavaWorld 偷了这个类加载器只是为了玩弄它)

public class SimpleClassLoader extends ClassLoader {
private HashMap<String, Class> classes = new HashMap<String, Class>();

public SimpleClassLoader() {
}

/**
 * This sample function for reading class implementations reads
 * them from the local file system
 */
private byte getClassImplFromDataBase(String className)[] {
    System.out.println("        >>>>>> Fetching the implementation of "+className);
    byte result[];
    try {
        FileInputStream fi = new FileInputStream("store\\"+className+".impl");
        result = new byte[fi.available()];
        fi.read(result);
        return result;
    } catch (Exception e) {

        /*
         * If we caught an exception, either the class wasnt found or it
         * was unreadable by our process.
         */
        return null;
    }
}

/**
 * This is a simple version for external clients since they
 * will always want the class resolved before it is returned
 * to them.
 */
public Class loadClass(String className) throws ClassNotFoundException {
    return (loadClass(className, true));
}

/**
 * This is the required version of loadClass which is called
 * both from loadClass above and from the internal function
 * FindClassFromClass.
 */
public synchronized Class loadClass(String className, boolean resolveIt)
    throws ClassNotFoundException {
    Class result;
    byte  classData[];

    System.out.println(className);

    System.out.println("        >>>>>> Load class : "+className);

    /* Check our local cache of classes */
    result = (Class)classes.get(className);
    if (result != null) {
        System.out.println("        >>>>>> returning cached result.");
        return result;
    }

    /* Check with the primordial class loader */
    try {
        result = super.findSystemClass(className);
        System.out.println("        >>>>>> returning system class (in CLASSPATH).");
        return result;
    } catch (ClassNotFoundException e) {
        System.out.println("        >>>>>> Not a system class.");
    }

    /* Try to load it from our repository */
    classData = getClassImplFromDataBase(className);
    if (classData == null) {
        throw new ClassNotFoundException();
    }

    /* Define it (parse the class file) */
    result = defineClass(classData, 0, classData.length);
    if (result == null) {
        throw new ClassFormatError();
    }

    if (resolveIt) {
        resolveClass(result);
    }

    classes.put(className, result);
    System.out.println("        >>>>>> Returning newly loaded class.");
    return result;
}
}

然后我决定测试一下:


public class Test
{
public static void main(String args[]) throws ClassNotFoundException
{
    SimpleClassLoader s = new SimpleClassLoader();
    Thread.currentThread().setContextClassLoader(s);

    Foo myfoo = new Foo();                          //local class
    ArrayList myList = new ArrayList();             //class from JAR file

    //both should have been loaded from my SimpleClassLoader
    System.out.println(s + "\n\tshould be equal to\n" + myfoo.getClass().getClassLoader());
    System.out.println("\tand also to: \n" + myList.getClass().getClassLoader());

    /*
       OUTPUT: 

       SimpleClassLoader@57fee6fc
            should be equal to
       sun.misc.Launcher$AppClassLoader@51f12c4e
            and also to: 
       null

       ***

       bizarre results: why are ArrayList and Foo not being loaded by my classloader?

     */


}
}
  1. 创建自定义 ClassLoader 是否是解决顶部描述的问题的正确方法?

  2. 为什么要调用系统类加载器?如何强制 JVM 为所有线程使用我的类加载器?(不仅仅是第一个线程,我希望创建的每个新线程都自动使用我的类加载器)

  3. 据我了解,通过“委托系统”,父类加载器首先尝试加载类;这可能是我的 ClassLoader 没有加载任何内容的原因。如果我是正确的,如何禁用此功能?如何让我的类加载器进行加载?

【问题讨论】:

标签: java class jar classloader delegation


【解决方案1】:

instrumentation api 非常适合我认为您正在尝试做的事情

http://docs.oracle.com/javase/6/docs/api/java/lang/instrument/Instrumentation.html

它可以让您在 JVM 加载类时拦截它们——通常是为了修改它们,但是您可以使用字节数组,所以我看不出为什么您不能在没有实际修改的情况下执行任何必需的分析。

这可以让您在加载类之前对其进行分析。我不完全清楚你想要实现什么,但如果你可以在加载类后分析它们,那么你可以简单地打开并解析类路径上所有 jar 的内容。

【讨论】:

  • 我查看了您提供的链接并在 Google 上搜索了 Instrumentation,但在这两种情况下,我都不确定我在看什么……如何在加载类时拦截它们?如果您能指出我应该覆盖哪些类/应该简要调用哪些方法,将不胜感激
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多