Một cách để làm điều này sẽ được để viết một tác nhân Java sử dụng instrumentation API. Điều này sẽ cho phép bạn ghi lại tải các lớp của 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
Nhược điểm là bạn phải tải các đại lý khi bạn khởi động JVM:
java -javaagent:myagent.jar ....etcetera
Chỉ cần một lưu ý phụ: Hãy nhớ sử dụng tên chuẩn package.subpackage.ClassName khi gọi phương thức. Câu trả lời này không thể hiện yêu cầu này vì lớp không nằm trong gói. –
Cảm ơn bạn đã thêm ghi chú đó. Trong khi bạn cần gói, nó là "tên nhị phân" được yêu cầu. Tên chuẩn của lớp được hiển thị trong ví dụ là "TestLoaded.ClassToTest", khác với tên nhị phân ... Tôi sẽ chỉnh sửa câu trả lời để làm rõ/liên kết. –
Cảm ơn @spdenne và @Aleksi. Tôi đã cố gắng làm điều này nhưng nó thất bại, mặc dù tôi không chắc tại sao. Mã của bạn ở trên không hoạt động cho tôi. Là một lưu ý phụ, bạn có thể muốn kiểm tra câu trả lời của McDowell về thiết bị đo đạc. Cảm ơn rất nhiều. –