0

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

4

1 回答 1

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);
    }
}

要将类转换为代理,您需要将其专门打包到带有适当清单的 JAR 文件中。清单是:

Premain-Class: ClassReporter

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

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

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

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

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

于 2013-01-04T00:39:17.837 回答