Java에서는 클래스가 이미로드되었는지 여부를 알 수 있습니까?

StackOverflow https://stackoverflow.com/questions/482633

  •  20-08-2019
  •  | 
  •  

문제

Java 클래스가로드되었는지 여부를 알 수 있습니까? 없이 로드하려고합니까? Class.forName 클래스를로드하려고 시도하지만이 부작용을 원하지 않습니다. 다른 방법이 있습니까?

(클래스 로더를 무시하고 싶지 않습니다. 비교적 간단한 방법을 찾고 있습니다.)

도움이 되었습니까?

해결책

(알렉시 덕분에)이 코드 :

public class TestLoaded {
     public static void main(String[] args) throws Exception {
          java.lang.reflect.Method m = ClassLoader.class.getDeclaredMethod("findLoadedClass", new Class[] { String.class });
          m.setAccessible(true);
          ClassLoader cl = ClassLoader.getSystemClassLoader();
          Object test1 = m.invoke(cl, "TestLoaded$ClassToTest");
          System.out.println(test1 != null);
          ClassToTest.reportLoaded();
          Object test2 = m.invoke(cl, "TestLoaded$ClassToTest");
          System.out.println(test2 != null);
     }
     static class ClassToTest {
          static {
               System.out.println("Loading " + ClassToTest.class.getName());
          }
          static void reportLoaded() {
               System.out.println("Loaded");
          }
     }
}

생산 :

false
Loading TestLoaded$ClassToTest
Loaded
true

예제 클래스는 패키지에 없습니다. 전체 이진 이름 필요합니다.

이진 이름의 예는 다음과 같습니다 "java.security.KeyStore$Builder$FileBuilder$1"

다른 팁

당신은 사용할 수 있습니다 findloadedClass (String) 클래스 로더의 메소드. 클래스가로드되지 않으면 NULL을 반환합니다.

이를 수행하는 한 가지 방법은 계측 API. 이를 통해 JVM의 클래스로드를 기록 할 수 있습니다.

public class ClassLoadedAgent implements ClassFileTransformer {

    private static ClassLoadedAgent AGENT = null;

    /** Agent "main" equivalent */
    public static void premain(String agentArguments,
            Instrumentation instrumentation) {
        AGENT = new ClassLoadedAgent();
        for (Class<?> clazz : instrumentation.getAllLoadedClasses()) {
            AGENT.add(clazz);
        }
        instrumentation.addTransformer(AGENT);
    }

    private final Map<ClassLoader, Set<String>> classMap = new WeakHashMap<ClassLoader, Set<String>>();

    private void add(Class<?> clazz) {
        add(clazz.getClassLoader(), clazz.getName());
    }

    private void add(ClassLoader loader, String className) {
        synchronized (classMap) {
            System.out.println("loaded: " + className);
            Set<String> set = classMap.get(loader);
            if (set == null) {
                set = new HashSet<String>();
                classMap.put(loader, set);
            }
            set.add(className);
        }
    }

    private boolean isLoaded(String className, ClassLoader loader) {
        synchronized (classMap) {
            Set<String> set = classMap.get(loader);
            if (set == null) {
                return false;
            }
            return set.contains(className);
        }
    }

    @Override
    public byte[] transform(ClassLoader loader, String className,
            Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
            byte[] classfileBuffer) throws IllegalClassFormatException {
        add(loader, className);
        return classfileBuffer;
    }

    public static boolean isClassLoaded(String className, ClassLoader loader) {
        if (AGENT == null) {
            throw new IllegalStateException("Agent not initialized");
        }
        if (loader == null || className == null) {
            throw new IllegalArgumentException();
        }
        while (loader != null) {
            if (AGENT.isLoaded(className, loader)) {
                return true;
            }
            loader = loader.getParent();
        }
        return false;
    }

}

Meta-Inf/Manifest.mf :

Manifest-Version: 1.0 
Premain-Class: myinstrument.ClassLoadedAgent

단점은 JVM을 시작할 때 에이전트를로드해야한다는 것입니다.

java -javaagent:myagent.jar ....etcetera

만약에 당신은 그들이로드되었는지 여부에 관심이있는 클래스의 출처를 제어하고 있습니다 (의심하지만 의심 스럽지만 질문에 언급하지 않습니다). 그러면 정적 이니셜 라이저에로드를 등록 할 수 있습니다.

public class TestLoaded {
    public static boolean loaded = false;
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(loaded);
        ClassToTest.reportLoaded();
        System.out.println(loaded);
    }
    static class ClassToTest {
        static {
            System.out.println("Loading");
            TestLoaded.loaded = true;
        }
        static void reportLoaded() {
            System.out.println("Loaded");
        }
    }
}

산출:

false
Loading
Loaded
true

나는 최근에 비슷한 문제가 있었는데, 나중에 나중에 내 클래스 로더에로드하고 있던 클래스와 충돌하는 사용자들에 의해 클래스가로드되고 있다고 의심했다 (아마도 classpath 또는 이와 유사한 것을 통해).

여기에 언급 된 것들 중 몇 가지를 시도한 후, 다음은 저를 위해 트릭을하는 것처럼 보였습니다. 모든 상황에서 작동하는지 확실하지 않으며 JAR 파일에서로드 된 Java 클래스에서만 작동 할 수 있습니다.

InputStream is = getResourceAsStream(name);

어디에 name 다음과 같은 클래스 파일의 경로입니다 com/blah/blah/blah/foo.class.

getResourceAsStream 반환 null 클래스가 내 클래스 로더 또는 시스템 클래스 로더에로드되지 않았고 클래스가 이미로드되었을 때 널을 반환했습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top