In many situations is it helpful to add own functionality to running (production) code - for debugging/tracing purpose or anything else.
In this case we can use the Java Intrumentation API and Javassist to add our functionalities at runtime. The Java Intrumentation API give us a hook point to instrument any loaded classes. Javassist is a bytecode manipulation library, it can modify and enhance any java bytecode.
In this case we can use the Java Intrumentation API and Javassist to add our functionalities at runtime. The Java Intrumentation API give us a hook point to instrument any loaded classes. Javassist is a bytecode manipulation library, it can modify and enhance any java bytecode.
public static void premain(String agentArgs, Instrumentation instrumentation) {
instrumentation.addTransformer( new LoggerAgent() );
}The ClassFileTransformer#transform() method is called for any class loaded by the java runtime.byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatExceptionSo now we can start with Javassist to modify/enhance the loaded class and inject some fields/methods and so on. First we must load the bytecode and build a Javasisst class instance, then we can add some fields and/or code that is invoked before a method is called or after a method is called.
ClassPool pool = ClassPool.getDefault();
CtClass cl = pool.makeClass( new java.io.ByteArrayInputStream( b ) );
if( cl.isInterface() == false ) {
// adds a class field
CtField field = CtField.make("String myField", cl );
cl.addField( field, "my initial value" );
CtBehavior[] methods = cl.getDeclaredBehaviors();
for( CtBehavior[] method : methods ) {
if( method.isEmpty() == false ) {
// inject some code before/after a method is called
method.insertBefore( "System.out.println(\"called before\");" );
method.insertAfter( "System.out.println(\"called after\");" );
}
}
b = cl.toBytecode();
}
return b;So now we are able to build the agent jar. In the maven project it use the maven-assembly-plugin to create a "fat jar" that includes also the dependencies to Javasisst and slf4j. Simply run mvn clean package and take the "fat jar" from the /target folder.Now start the java runtime command line with the javaagent attribut:
java -javaagent:loggingagent-0.0.1-SNAPSHOT-jar-with-dependencies.jar ...
The example code can be loaded from https://github.com/kreyssel/maven-examples/tree/master/javaagent/.
This was inspired by blog post: http://today.java.net/article/2008/04/22/add-logging-class-load-time-java-instrumentation