Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Oredev 2015 - Taming Java Agents

Oredev 2015 - Taming Java Agents

Java agents are pluggable self contained components that run embedded in a JVM and intercept the classloading process. They were introduced in Java 5 along with the powerful java.lang.instrument package. Java agents can be loaded statically at startup or dynamically (programmatically) at runtime to attach to a running process.

Java agents were an awesome addition to the JVM as it opened a lot of opportunities for tool designers and changed Java tooling landscape quite drastically. In conjunction with Java bytecode manipulation libraries it is now possible to do amazing things to Java classes: we can experiment with programming models, redefine classes at runtime, record execution flow, etc.

I’d like to give an overview of Java agents’ functionality along with the usage examples and real world experiences. You will learn, how to implement an agent and apply Instrumentation API in combination with bytecode manipulation libraries to solve interesting tasks.

1bc80e2eee2adeaa8bb577798d92e9d0?s=128

Anton Arhipov

November 05, 2015
Tweet

Transcript

  1. Taming Java Agents @antonarhipov

  2. Me Anton Arhipov @antonarhipov anton@zeroturnaround.com ZeroTurnaround JRebel, XRebel

  3. None
  4. Agenda • Overview of Java agent technology • Instrumentation API

    • Attach API • HacksApplications http://xkcd.com/138/
  5. BTrace

  6. Pretty much every APM tool today uses Java Agents to

    instrument the application
  7. A lightweight profiler for Java web apps

  8. A lightweight profiler for Java web apps

  9. A lightweight profiler for Java web apps

  10. A lightweight profiler for Java web apps

  11. A lightweight profiler for Java web apps

  12. A lightweight profiler for Java web apps

  13. None
  14. None
  15. None
  16. my.war ClassLoader getResource("hello.html"); read("src/main/.../hello.html"); rebel.xml • Maps the running application

    to IDE workspace • Reloads Java classes and framework configurations in a running JVM process
  17. This slide is intentionally left blank

  18. None
  19. public static void main(String[] args) {
 for (String arg :

    args) {
 new Thread(new Runnable() {
 public void run() {
 //....
 }
 }).start(); Java app
  20. public static void main(String[] args) {
 for (String arg :

    args) {
 new Thread(new Runnable() {
 public void run() {
 //.....
 }
 }).start(); RULE  trace  thread  start   CLASS  java.lang.Thread   METHOD  start()   IF  true   DO  traceln("***  start  for  thread:  "+  $0.getName())   ENDRULE Java app Byteman rule
  21. public static void main(String[] args) {
 for (String arg :

    args) {
 new Thread(new Runnable() {
 public void run() {
 //.....
 }
 }).start(); RULE  trace  thread  start   CLASS  java.lang.Thread   METHOD  start()   IF  true   DO  traceln("***  start  for  thread:  "+  $0.getName())   ENDRULE > java -javaagent:byteman.jar=script:thread.btm,boot:byteman.jar \ -Dorg.jboss.byteman.transform.all org.my.AppMain2 foo bar baz *** start for thread: foo foo *** start for thread: bar bar *** start for thread: baz baz Java app Byteman rule
  22. public static void main(String[] args) {
 for (String arg :

    args) {
 new Thread(new Runnable() {
 public void run() {
 //.....
 }
 }).start(); RULE  trace  thread  start   CLASS  java.lang.Thread   METHOD  start()   IF  true   DO  traceln("***  start  for  thread:  "+  $0.getName())   ENDRULE Java app Byteman rule
  23. public static void main(String[] args) {
 for (String arg :

    args) {
 new Thread(new Runnable() {
 public void run() {
 //.....
 }
 }).start(); RULE  trace  thread  start   CLASS  java.lang.Thread   METHOD  start()   IF  true   DO  traceln("***  start  for  thread:  "+  $0.getName())   ENDRULE > java -classpath byteman-install.jar \ org.jboss.byteman.agent.install.Install 13101 Java app Byteman rule Install agent:
  24. public static void main(String[] args) {
 for (String arg :

    args) {
 new Thread(new Runnable() {
 public void run() {
 //.....
 }
 }).start(); RULE  trace  thread  start   CLASS  java.lang.Thread   METHOD  start()   IF  true   DO  traceln("***  start  for  thread:  "+  $0.getName())   ENDRULE > java -classpath byteman-install.jar \ org.jboss.byteman.agent.install.Install 13101 Java app Byteman rule > java -classpath byteman-submit.jar \ org.jboss.byteman.agent.submit.Submit -l thread.btm Install agent: Submit rules:
  25. http://byteman.jboss.org

  26. Java Agent Overview

  27. import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; public class Agent { public static

    void premain(String args, Instrumentation inst) { inst.addTransformer(new ClassFileTransformer { … }); } public static void agentmain(String args, Instrumentation inst) { premain(args, inst); } } META-­‐INF/MANIFEST.MF   Premain-­‐Class:  Agent $>  java  –javaagent:agent.jar  application.Main
  28. java.lang.instrument.ClassFileTransformer public class MyTransformer implements ClassFileTransformer { public void byte[]

    transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain pd, byte[] classfileBuffer){ ClassPool cp = ClassPool.getDefault(); CtClass ct = cp.makeClass(new ByteArrayInputStream(classfileBuffer)); // transform the bytes as required, // for instance - with Javassist return ct.toBytecode(); } }
  29. Class loading Instrumentation

  30. Class loading ClassFileTransformer ClassFileTransformer ClassFileTransformer Instrumentation

  31. Class loading ClassFileTransformer ClassFileTransformer ClassFileTransformer Javassist ASM Instrumentation Bytebuddy

  32. https://github.com/zeroturnaround/callspy

  33. Instrumentation API

  34. java.lang.instrument.Instrumentation void addTransformer(ClassFileTransformer transformer, boolean canRetransform); void appendToBootstrapClassLoaderSearch(JarFile jarfile); void

    appendToSystemClassLoaderSearch(JarFile jarfile); Class[] getAllLoadedClasses(); Class[] getInitiatedClasses(ClassLoader loader); void redefineClasses(ClassDefinition... classes); void retransformClasses(Class<?>... classes);
  35. JVM JVM Process 1 Process 2 Agent -cp tools.jar Attach

    API
  36. • Executed when the agent attaches to the running JVM

    • Instrumentation parameter is optional • META-INF/MANIFEST.MF is required • Requires support for loading agents in JVM • Allows adding the code to JVM post-factum public static void agentmain(String args, Instrumentation inst)
  37. import com.sun.tools.attach.VirtualMachine; //attach to target VM VirtualMachine vm = VirtualMachine.attach("2177");

    //get system properties in the target VM Properties props = vm.getSystemProperties(); //load agent into the VM vm.loadAgent("agent.jar", "arg1=x,arg2=y"); //detach from VM vm.detach(); http://docs.oracle.com/javase/7/docs/jdk/api/attach/spec/com/sun/tools/attach/VirtualMachine.html
  38. https://gist.github.com/nickman/6494990 https://github.com/antonarhipov/attach-and-transform-with-mbeans

  39. https://speakerdeck.com/antonarhipov http://www.slideshare.net/arhan @antonarhipov anton@zeroturnaround.com

  40. Resources http://byteman.jboss.org http://www.javassist.org https://github.com/zeroturnaround/callspy https://github.com/antonarhipov/attach-and-transform-with-mbeans https://docs.oracle.com/javase/8/docs/api/java/lang/instrument/package- summary.html http://docs.oracle.com/javase/8/docs/jdk/api/attach/spec/com/sun/tools/ attach/VirtualMachine.html http://asm.ow2.org/

    http://bytebuddy.net/