如何从JVM获取有关加载哪些类以及所有已加载类的规范的信息?

时间:2013-01-03 23:21:41

标签: java

我想获取所有已加载类的信息,以及类的规范,例如哪些方法及其签名,方法可以抛出什么样的异常。等等 我知道以前的帖子说过如何加载所有类,但没有其他详细信息,所以有没有可用的东西可以得到我想要的东西?

1 个答案:

答案 0 :(得分:2)

正如其他人在其他地方提到的那样,您可以通过将代理程序附加到JVM来完成此操作,因为这是JVM将报告加载哪些类的唯一位置。

本课程展示了如何完成:

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

public class ClassReporter implements Runnable {
    /** Output file */
    File output;

    /** The JVM instrumentation */
    Instrumentation instrument;

    /** Already reported classes */
    Set<Class<?>> known = new HashSet<Class<?>>();

    /** Is reporter still running? */
    volatile boolean running = true;


    @Override
    public void run() {
        System.out.println("Class Reporter agent running");
        while( running ) {
            if (!report()) return;
            try {
                Thread.sleep(5000);
            } catch (InterruptedException ie) {
                ie.printStackTrace();
                return;
            }
        }
    }


    /**
     * Update the report of loaded classes
     * 
     * @return true if report was written OK
     */
    public synchronized boolean report() {
        Set<Class<?>> report = new HashSet<Class<?>>();
        Class<?>[] classes = instrument.getAllLoadedClasses();
        for(Class<?> c:classes) {
            if (known.add(c)) report.add(c);
        }
        if (report.isEmpty()) return true;

        boolean ret = true;
        FileWriter fw = null;
        try {
            fw = new FileWriter(output, true);
            for(Class<?> c:classes) {
                fw.write(c.getName());
                fw.write('\n');

                for(Method m:c.getDeclaredMethods()) {
                    fw.write(m.toGenericString());
                    fw.write('\n');
                }
                fw.write('\n');
                fw.write('\n');
                fw.flush();
            }
        } catch (IOException ioe) {
            ioe.printStackTrace();
            ret = false;
        } finally {
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    ret = false;
                }
            }
        }
        return ret;
    }


    /**
     * Initialize the reporter
     * 
     * @param agentArgs
     *            the output file name
     * @param inst
     *            the instrumentation
     */
    public static void premain(String agentArgs, Instrumentation inst) {
        final ClassReporter cr = new ClassReporter();
        cr.instrument = inst;
        File out = new File(agentArgs);
        out.delete();
        try {
            out.createNewFile();
        } catch (IOException ioe) {
            System.out.println("Class Reporter could not create file "
                    + out.getAbsolutePath());
            return;
        }
        cr.output = out;

        Thread thread = new Thread(cr);
        thread.setDaemon(true);
        thread.start();

        Thread shutdown = new Thread() {
            public void run() {
                System.out.println("Class Reporter writing final report");
                cr.running = false;
                cr.report();
                System.out.println("Class Reporter done");
            }
        };

        Runtime.getRuntime().addShutdownHook(shutdown);
    }
}

要将类转换为代理,您需要将其特别打包在具有适当Manifest的JAR文件中。清单是:

Premain-Class: ClassReporter

然后使用以下命令创建代理jar:

jar cvfm cr.jar Manifest.mf ClassReporter*.class

然后实际使用它,运行应用程序在命令行上指定代理程序,如下所示:

java -javaagent:cr.jar=cr.txt ActualProgramMainClass

“cr.txt”是生成的输出文件。你会看到System.out上的输出说记者正在运行。输出文件显示您在问题中提到的所有信息。