One way of achieving this is replacing the boot classloader and finding a way to keep a reference to every loaded class by every child classloader. This sounded like too much work and I find it very scary to replace system classes with my own which probably don't have the same quality.
Another approach is to write a javaagent. This gives access to the java.lang.instrument.Instrumentation class which in turn has the getAllLoadedClasses() method. Exactly the information I was after and without many nasty side effects or jumping through burning hoops.
Now that I found this information I needed a way to publish it. A colleague of mine pointed me in the direction of JMX. Using JConsole to view which classes are loaded sound great to me so after a little hacking I came up with a javaagent which registers itself as an MBean.
Here's the code:
MANIFEST.MF
Manifest-Version: 1.0
Premain-Class: somecoder.classes.Classes
ClassesMBean.java
package somecoder.classes;
public interface ClassesMBean {
String[] getClasses();
long getClassCount();
}
Classes.java
package somecoder.classes;
import java.lang.instrument.Instrumentation;
import java.lang.management.ManagementFactory;
import javax.management.ObjectName;
public final class Classes implements ClassesMBean {
private Instrumentation inst;
private Classes(final Instrumentation inst) {
this.inst = inst;
}
public static void premain(final String agentArgs,
final Instrumentation inst) {
try {
final Classes classLister = new Classes(inst);
ManagementFactory.getPlatformMBeanServer().registerMBean(classLister, new ObjectName("Classes:type=Agent"));
} catch (Exception e) {
e.printStackTrace();
}
}
public long getClassCount() {
return inst.getAllLoadedClasses().length;
}
public String[] getClasses() {
final Class[] classes = inst.getAllLoadedClasses();
final String[] strings = new String[classes.length];
for (int i = 0; i < classes.length; i++) {
strings[i] = classes[i].getName();
}
return strings;
}
}
No comments:
Post a Comment