Friday, February 29, 2008

Every Class

This week I wanted to find out which classes are loaded in running environment.

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: