1

我正在编写一个游戏引擎,我需要在其中分析程序中提到的每一个类。由于这是一个游戏引擎,它会以 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 没有加载任何内容的原因。如果我是正确的,如何禁用此功能?如何让我的类加载器进行加载?

4

1 回答 1

2

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

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

It lets you intercept classes as they are loaded by the JVM - normally to modify them, but you are given the byte array to play with so I can see no reason why you couldn't perform any required analysis without actually modifying.

This would let you analyse classes before they are loaded. I'm not entirely clear on what it is you are trying to achieve, but if you can analyse the classes after they are loaded then you could simply open and parse the contents of all jars on the classpath.

于 2012-04-17T20:29:23.190 回答