Using Java Instrumentation and Javassist for Non‑Intrusive Performance Monitoring
This article demonstrates how to employ Java's java.lang.instrument API together with Javassist to create a Java agent that instruments bytecode at runtime, enabling performance monitoring without modifying the original application code.
Java dynamic proxies can only proxy interfaces, which limits their use for non‑intrusive performance monitoring; the article introduces Java Instrumentation, a Java SE 5 feature that allows developers to write agents that monitor and modify classes at runtime.
Instrumentation, provided by java.lang.instrument , frees instrumentation from native code and enables Java‑level solutions such as agents that can observe, replace, or alter class definitions while the JVM runs.
The java.lang.instrument package offers services for monitoring programs on the JVM by modifying method bytecode, and the article combines this capability with the Javassist library to achieve decoupled performance monitoring.
1. Define an Instrument class that implements the premain method
The required premain method is invoked by the JVM before the application starts; the agent JAR must be loaded by the system class loader. (Image showing the code structure.)
Note: If the agent cannot be resolved (e.g., the class cannot be loaded or the premain method is missing), the JVM will abort. If the premain method throws an uncaught exception, the JVM will also abort.
2. Implement the ClassFileTransformer interface
The core class PerformanceMetric implements ClassFileTransformer and overrides transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) . This method receives the bytecode of each loaded class and injects performance‑testing code into selected methods (e.g., login ) using Javassist.
(Image illustrating the transformer implementation.)
Within transform , Javassist’s CtClass.getDeclaredMethod retrieves all methods, iterates to find the target, and then uses CtMethod.insertBefore and CtMethod.insertAfter to insert timing code. (Image showing the insertion code.)
3. Write the business‑logic code
A simple Userservice class with a login method that sleeps for 100 ms is used to demonstrate the monitoring effect.
(Image of the Userservice source.)
4. Package the agent into a JAR
The agent JAR must contain a MANIFEST.MF with the attribute Premain-Class: com.w3tech.instrument.Instrument to designate the class that provides the premain method.
(Image of the manifest configuration.)
5. Run the application with the agent
Start the JVM with the option -javaagent:/path/to/agent.jar[=options] , where the path points to the built JAR and optional arguments can be supplied.
(Image showing the command‑line execution.)
6. Summary
The tutorial shows that java.lang.instrument provides powerful capabilities for extending applications without source changes; most commercial APM solutions for Java also rely on instrumentation, and further exploration of this API can greatly benefit developers interested in runtime monitoring.
Art of Distributed System Architecture Design
Introductions to large-scale distributed system architectures; insights and knowledge sharing on large-scale internet system architecture; front-end web architecture overviews; practical tips and experiences with PHP, JavaScript, Erlang, C/C++ and other languages in large-scale internet system development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.