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

Taming Java Agents - JavaOne, CON2578

Anton Arhipov
September 23, 2013

Taming Java Agents - JavaOne, CON2578

Overview of the Java agent technology applied in JRebel & Plumbr

Anton Arhipov

September 23, 2013
Tweet

More Decks by Anton Arhipov

Other Decks in Programming

Transcript

  1. Why are you here? • Are you interested in Java

    agent technology? • Have you read the abstract? • Are you interested in JRebel or Plumbr? • Other ... Tuesday, September 24, 13
  2. This talk is about ... ... technical aspects of Java

    agent technology and how and leverage it Tuesday, September 24, 13
  3. public void doSomething(){ // no logging here stmt; stmt; stmt;

    stmt; stmt; stmt; stmt; } Tuesday, September 24, 13
  4. public void doSomething(){ // no logging here stmt; // argh!

    stmt; stmt; stmt; stmt; stmt; } java.lang.RuntimeException: blah! at org.springframework.samples.petclinic.validation.OwnerValidator.doSomething(OwnerValidator.java:41) at org.springframework.samples.petclinic.web.AddOwnerForm.processSubmit(AddOwnerForm.java:60) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:790) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:719) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:644) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:560) at javax.servlet.http.HttpServlet.service(HttpServlet.java:641) at javax.servlet.http.HttpServlet.service(HttpServlet.java:722) Tuesday, September 24, 13
  5. public void doSomething(){ // no logging here stmt; // argh!

    stmt; stmt; stmt; stmt; stmt; } If only I could add some logging ... Tuesday, September 24, 13
  6. public static void main(String[] args) { for (String arg :

    args) { new Thread(new Runnable() { public void run() { //..... } }).start(); Java app Tuesday, September 24, 13
  7. 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 Tuesday, September 24, 13
  8. 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 Tuesday, September 24, 13
  9. 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 Tuesday, September 24, 13
  10. 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: Tuesday, September 24, 13
  11. 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: Tuesday, September 24, 13
  12. 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); } } Tuesday, September 24, 13
  13. • java -javaagent:<jarfile>[=options] • Instrumentation parameter is optional • META-INF/MANIFEST.MF

    is required public static void premain(String args, Instrumentation inst) Tuesday, September 24, 13
  14. • 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) Tuesday, September 24, 13
  15. Manifest.mf Manifest-Version: 1.0 Ant-Version: Apache Ant 1.8.1 Created-By: 1.7.0_15-b03 (Oracle

    Corporation) Premain-Class: com.zeroturnaround.javarebel.java5.AgentInstall Can-Redefine-Classes: true Boot-Class-Path: jrebel.jar Main-Class: com.zeroturnaround.javarebel.java4.Install Implementation-Title: JRebel Specification-Title: jrebel Specification-Version: 5.4.0 Implementation-Version: 201309021535 Tuesday, September 24, 13
  16. 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 Tuesday, September 24, 13
  17. 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); Tuesday, September 24, 13
  18. 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(); } } Tuesday, September 24, 13
  19. 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(); } } Tuesday, September 24, 13
  20. Javassist • Bytecode manipulation made easy • Source-leve and bytecode-leve

    API • Users the vocabulary of Java language • On-the-fly compilation of the injected code • http://www.jboss.org/javassist Tuesday, September 24, 13
  21. CtClass ct = cp.get("org.jboss.weld.bean.AbstractBean"); ct.addInterface(cp.get(ClassEventListener.class.getName())); ct.addMethod(CtNewMethod.make( "public int priority() {

    " return ClassEventListener.PRIORITY_DEFAULT + 100; " + }", cls)); ct.addMethod(CtNewMethod.make( "public void onClassEvent(int eventType, Class clazz) { " + // ... "}", cls)); Tuesday, September 24, 13
  22. CtClass ct = cp.get("org.jboss.weld.bean.AbstractBean"); ct.addInterface(cp.get(ClassEventListener.class.getName())); ct.addMethod(CtNewMethod.make( "public int priority() {

    " return ClassEventListener.PRIORITY_DEFAULT + 100; " + }", cls)); ct.addMethod(CtNewMethod.make( "public void onClassEvent(int eventType, Class clazz) { " + // ... "}", cls)); Tuesday, September 24, 13
  23. CtClass ct = cp.get("org.jboss.weld.bean.AbstractBean"); ct.addInterface(cp.get(ClassEventListener.class.getName())); ct.addMethod(CtNewMethod.make( "public int priority() {

    " return ClassEventListener.PRIORITY_DEFAULT + 100; " + }", cls)); ct.addMethod(CtNewMethod.make( "public void onClassEvent(int eventType, Class clazz) { " + // ... "}", cls)); Tuesday, September 24, 13
  24. CtClass ct = cp.get("org.jboss.weld.bean.AbstractBean"); ct.addInterface(cp.get(ClassEventListener.class.getName())); ct.addMethod(CtNewMethod.make( "public int priority() {

    " return ClassEventListener.PRIORITY_DEFAULT + 100; " + }", cls)); ct.addMethod(CtNewMethod.make( "public void onClassEvent(int eventType, Class clazz) { " + // ... "}", cls)); Tuesday, September 24, 13
  25. CtClass ct = cp.get("org.jboss.weld.bean.AbstractBean"); ct.addInterface(cp.get(ClassEventListener.class.getName())); ct.addMethod(CtNewMethod.make( "public int priority() {

    " return ClassEventListener.PRIORITY_DEFAULT + 100; " + }", cls)); ct.addMethod(CtNewMethod.make( "public void onClassEvent(int eventType, Class clazz) { " + // ... "}", cls)); return ct.toBytecode(); Tuesday, September 24, 13
  26. • Maps the running application to IDE workspace • Reloads

    Java classes in a running JVM process • Integrates with Java ecosystem • Java application servers / containers • Java application frameworks • Reloads configurations and meta-data • IDE plugins Tuesday, September 24, 13
  27. Plumbr • Estonian startup trying to solve performance problems •

    We started with memory leaks and solved them :) • Ongoing effort, more problems to be solved Tuesday, September 24, 13
  28. Summary • Instrumentation API is a foundation for awesome Java

    tooling • JRebel can reload classes and framework configurations on the fly • Plumbr detects memory leaks and researches performance problems Tuesday, September 24, 13