Programing

Java-JVM에로드 된 모든 클래스 목록 가져 오기

lottogame 2020. 11. 23. 07:36
반응형

Java-JVM에로드 된 모든 클래스 목록 가져 오기


특정 패키지에 속한 모든 클래스와 모든 자녀의 목록을 얻고 싶습니다. 클래스는 JVM에 이미로드되었거나로드되지 않았을 수 있습니다.


프로그래밍 방식 솔루션은 아니지만 실행할 수 있습니다.

java -verbose:class ....

JVM은로드되는 내용과 위치를 덤프합니다.

[Opened /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/sunrsasign.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jsse.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/jce.jar]
[Opened /usr/java/j2sdk1.4.1/jre/lib/charsets.jar]
[Loaded java.lang.Object from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.io.Serializable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.Comparable from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.CharSequence from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]
[Loaded java.lang.String from /usr/java/j2sdk1.4.1/jre/lib/rt.jar]

자세한 내용은 여기 를 참조하십시오.


Reflections 라이브러리를 사용하면 다음과 같이 쉽습니다.

Reflections reflections = new Reflections("my.pkg", new SubTypesScanner(false));

my.pkg 패키지를 포함하는 url / s의 모든 클래스를 스캔합니다.

  • false 매개 변수는 기본적으로 제외되는 Object 클래스를 제외하지 않음을 의미합니다.
  • 일부 시나리오 (다른 컨테이너)에서는 classLoader와 매개 변수를 전달할 수 있습니다.

따라서 모든 클래스를 얻는 것은 전 이적으로 Object의 모든 하위 유형을 효과적으로 가져 오는 것입니다.

Set<String> allClasses = 
    reflections.getStore().getSubTypesOf(Object.class.getName());

(일반적인 방법 reflections.getSubTypesOf(Object.class)모든 클래스를 PermGen에 로드 하게하고 아마도 OutOfMemoryError를 던질 것입니다. 당신은 그것을 원하지 않을 것입니다 ...)

전이 하위 유형을 한 번에 모두 가져 오지 않고 Object (또는 다른 유형)의 모든 직접 하위 유형 을 가져 오려면 다음을 사용하십시오.

Collection<String> directSubtypes = 
    reflections.getStore().get(SubTypesScanner.class).get(Object.class.getName());

부분적으로 모호한 질문으로 인해이 질문에 대한 여러 답변이 있습니다. 제목은 JVM에 의해로드 된 클래스에 대해 말하는 반면 질문의 내용은 "JVM에 의해로드 될 수도 있고로드되지 않을 수도 있습니다."라고 말합니다.

OP에 주어진 클래스 로더에 의해 JVM에 의해로드되는 클래스가 필요하다고 가정하고 해당 클래스 만 필요하다고 가정하면 다음과 같은 솔루션 ( 여기에 자세히 설명 됨 )이 있습니다.

import java.net.URL;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;

public class CPTest {

    private static Iterator list(ClassLoader CL)
        throws NoSuchFieldException, SecurityException,
        IllegalArgumentException, IllegalAccessException {
        Class CL_class = CL.getClass();
        while (CL_class != java.lang.ClassLoader.class) {
            CL_class = CL_class.getSuperclass();
        }
        java.lang.reflect.Field ClassLoader_classes_field = CL_class
                .getDeclaredField("classes");
        ClassLoader_classes_field.setAccessible(true);
        Vector classes = (Vector) ClassLoader_classes_field.get(CL);
        return classes.iterator();
    }

    public static void main(String args[]) throws Exception {
        ClassLoader myCL = Thread.currentThread().getContextClassLoader();
        while (myCL != null) {
            System.out.println("ClassLoader: " + myCL);
            for (Iterator iter = list(myCL); iter.hasNext();) {
                System.out.println("\t" + iter.next());
            }
            myCL = myCL.getParent();
        }
    }

}

One of the neat things about it is that you can choose an arbitrary classloader you want to check. It is however likely to break should internals of classloader class change, so it is to be used as one-off diagnostic tool.


I'd also suggest you write a -javagent agent, but use the getAllLoadedClasses method instead of transforming any classes.

To synchronize with your client code (Normal Java code), create a socket and communicate with the agent through it. Then you can trigger a "list all classes" method whenever you need.


An alternative approach to those described above would be to create an external agent using java.lang.instrument to find out what classes are loaded and run your program with the -javaagent switch:

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

public class SimpleTransformer implements ClassFileTransformer {

    public SimpleTransformer() {
        super();
    }

    public byte[] transform(ClassLoader loader, String className, Class redefiningClass, ProtectionDomain domain, byte[] bytes) throws IllegalClassFormatException {
        System.out.println("Loading class: " + className);
        return bytes;
    }
}

This approach has the added benefit of providing you with information about which ClassLoader loaded a given class.


One way if you already know the package top level path is to use OpenPojo

final List<PojoClass> pojoClasses = PojoClassFactory.getPojoClassesRecursively("my.package.path", null);

Then you can go over the list and perform any functionality you desire.


You might be able to get a list of classes that are loaded through the classloader but this would not include classes you haven't loaded yet but are on your classpath.

To get ALL classes on your classpath you have to do something like your second solution. If you really want classes that are currently "Loaded" (in other words, classes you have already referenced, accessed or instantiated) then you should refine your question to indicate this.


Run your code under a JRockit JVM, then use JRCMD <PID> print_class_summary

This will output all loaded classes, one on each line.


From Oracle doc you can use -Xlog option that has a possibility to write into file.

java -Xlog:class+load=info:classloaded.txt

Well, what I did was simply listing all the files in the classpath. It may not be a glorious solution, but it works reliably and gives me everything I want, and more.


This program will prints all the classes with its physical path. use can simply copy this to any JSP if you need to analyse the class loading from any web/application server.

import java.lang.reflect.Field;
import java.util.Vector;

public class TestMain {

    public static void main(String[] args) {
        Field f;
        try {
            f = ClassLoader.class.getDeclaredField("classes");
            f.setAccessible(true);
            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Vector<Class> classes =  (Vector<Class>) f.get(classLoader);

            for(Class cls : classes){
                java.net.URL location = cls.getResource('/' + cls.getName().replace('.',
                '/') + ".class");
                System.out.println("<p>"+location +"<p/>");
            }
        } catch (Exception e) {

            e.printStackTrace();
        }
    }
}

참고URL : https://stackoverflow.com/questions/2548384/java-get-a-list-of-all-classes-loaded-in-the-jvm

반응형