Java Instrumentation API provides the ability to add byte-code to existing compiled Java classes.
Java Instrumentation will give a demonstration of how powerful Java is. Most importantly, this power can be realized by a developer for innovative means.
For example using Java instrumentation, we can access a class that is loaded by the Java classloader from the JVM and modify its bytecode by inserting our custom code, all these done at runtime.
Don’t worry about security, these are governed by the same security context applicable for Java classes and respective classloaders.
Agent – is a jar file containing agent and transformer class files.
Agent Class – A java class file, containing a method named
manifest.mffile containing the
Transformer – A Java class file implementing the interface
What Is a Java Agent
In general, a java agent is just a specially crafted jar file. It utilizes the Instrumentation API that the JVM provides to alter existing byte-code that is loaded in a JVM.
For an agent to work, we need to define two methods:
premain– will statically load the agent using -javaagent parameter at JVM startup
agentmain– will dynamically load the agent into the JVM using the Java Attach API
Instrumentation Activity Sequence
Loading a Java Agent
We have two types of load:
static – makes use of the
premainto load the agent using
dynamic – makes use of the
agentmainto load the agent into the JVM using the Java Attach API
Loading a Java agent at application startup is called static load. Static load modifies the byte-code at startup time before any code is executed.
Keep in mind that the static load uses the premain method, which will run before any application code runs, to get it running we can execute:
java -javaagent:agent.jar -jar application.jar
Launcher -> args:
StartMyAtmApplication 2 7 8
The procedure of loading a Java agent into an already running JVM is called dynamic load. The agent is attached using the Java Attach API.
A more complex scenario is when we already have our ATM application running in production and we want to add the total time of transactions dynamically without downtime for our application.
VirtualMachine jvm = VirtualMachine.attach(jvmPid); jvm.loadAgent(agentFile.getAbsolutePath()); jvm.detach();
Starting the Application:
java -jar application.jar StartMyAtmApplication
Attaching Java Agent:
java -jar application.jar LoadAgent
Check Application Logs
addTransformer– adds a transformer to the instrumentation engine
getAllLoadedClasses– returns an array of all classes currently loaded by the JVM
retransformClasses– facilitates the instrumentation of already loaded classes by adding byte-code
removeTransformer– unregisters the supplied transformer
redefineClasses– redefine the supplied set of classes using the supplied class files, meaning that the class will be fully replaced, not modified as with
Creating a Java Agent
Premain-transformClass(String className, Instrumentation instrumentation)
Creating an Agent Manifest File
We can find the full list of manifest attributes in the Instrumentation Package official documentation.
Agent-Class: com.baeldung.instrumentation.agent.MyInstrumentationAgent Can-Redefine-Classes: true Can-Retransform-Classes: true Premain-Class: com.baeldung.instrumentation.agent.MyInstrumentationAgent