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

JavaZone 2017 - The hitchhicker's guide to Java class reloading

JavaZone 2017 - The hitchhicker's guide to Java class reloading

1bc80e2eee2adeaa8bb577798d92e9d0?s=128

Anton Arhipov

September 13, 2017
Tweet

Transcript

  1. The hitchhiker’s guide to Java class reloading @antonarhipov

  2. whoami Anton Arhipov @antonarhipov

  3. whoami Anton Arhipov @antonarhipov

  4. None
  5. None
  6. https://zeroturnaround.com/rebellabs/java-ee-productivity-report-2011/ 10% 20% 30% 0.5 1 2 3 4 5

    6 7 8 10+ minutes
  7. https://zeroturnaround.com/rebellabs/java-ee-productivity-report-2011/ 10% 20% 30% 0.5 1 2 3 4 5

    6 7 8 10+ The only effective developers?? minutes
  8. https://zeroturnaround.com/rebellabs/java-ee-productivity-report-2011/ 10% 20% 30% 0.5 1 2 3 4 5

    6 7 8 10+ How about those? minutes
  9. None
  10. HotSwap

  11. HotSwap Class loaders

  12. HotSwap Class loaders Java agents & instrumentation

  13. HotSwap Class loaders Java agents & instrumentation

  14. hotswap EST. 2001

  15. None
  16. None
  17. None
  18. None
  19. None
  20. None
  21. None
  22. None
  23. None
  24. HOW ABOUT… refactoring?

  25. None
  26. None
  27. None
  28. JDB

  29. instanceKlass constantPoolOop constants() pool_holder() klassVTable Embedded klassITable Embedded Embedded statics

    M. Dmitriev. Safe class and data evolution in large and long-lived Java (тм) applications. Technical report, Mountain View. 2001
  30. instanceKlass constantPoolOop constants() constantPoolCacheOop cache() pool_holder() klassVTable Embedded klassITable Embedded

    Embedded statics M. Dmitriev. Safe class and data evolution in large and long-lived Java (тм) applications. Technical report, Mountain View. 2001
  31. instanceKlass constantPoolOop constants() constantPoolCacheOop cache() pool_holder() klassVTable Embedded klassITable Embedded

    Embedded statics objArrayOop methodOop methods() M. Dmitriev. Safe class and data evolution in large and long-lived Java (тм) applications. Technical report, Mountain View. 2001
  32. instanceKlass constantPoolOop constants() constantPoolCacheOop cache() pool_holder() klassVTable Embedded klassITable Embedded

    Embedded statics nmethod code() method() constants() objArrayOop methodOop methods() M. Dmitriev. Safe class and data evolution in large and long-lived Java (тм) applications. Technical report, Mountain View. 2001
  33. What if… hotswap++

  34. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L.

    Stadler. 2010
  35. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L.

    Stadler. 2010 Statements
  36. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L.

    Stadler. 2010 Statements Methods
  37. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L.

    Stadler. 2010 Statements Methods Fields
  38. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L.

    Stadler. 2010 Statements Methods Fields Hierarchy
  39. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L.

    Stadler. 2010 Statements Methods Fields Hierarchy
  40. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L.

    Stadler. 2010 Statements Methods Fields Hierarchy + + + Binary-compatible
  41. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L.

    Stadler. 2010 Statements Methods Fields Hierarchy + + + x x x Binary-compatible Binary-incompatible
  42. None
  43. Classloaders

  44. Class<?> uc1 = User.class; Class<?> uc2 = new DynamicClassLoader().load("com.zt.User"); out.println(uc1.getName());

    // com.zt.User out.println(uc2.getName()); // com.zt.User out.println(uc1.getClassLoader()); // sun.misc.Launcher$AppClassLoader@18b4aac2 out.println(uc2.getClassLoader()); // com.zt.DynamicClassLoader@22b4bba7 User.age = 11; out.println((int) ReflectUtil.getStaticFieldValue("age", uc1)); // 11 out.println((int) ReflectUtil.getStaticFieldValue("age", uc2)); // 10 public class User { public static int age = 10; }
  45. Class<?> uc1 = User.class; Class<?> uc2 = new DynamicClassLoader().load("com.zt.User"); out.println(uc1.getName());

    // com.zt.User out.println(uc2.getName()); // com.zt.User out.println(uc1.getClassLoader()); // sun.misc.Launcher$AppClassLoader@18b4aac2 out.println(uc2.getClassLoader()); // com.zt.DynamicClassLoader@22b4bba7 User.age = 11; out.println((int) ReflectUtil.getStaticFieldValue("age", uc1)); // 11 out.println((int) ReflectUtil.getStaticFieldValue("age", uc2)); // 10 public class User { public static int age = 10; }
  46. Class<?> uc1 = User.class; Class<?> uc2 = new DynamicClassLoader().load("com.zt.User"); out.println(uc1.getName());

    // com.zt.User out.println(uc2.getName()); // com.zt.User out.println(uc1.getClassLoader()); // sun.misc.Launcher$AppClassLoader@18b4aac2 out.println(uc2.getClassLoader()); // com.zt.DynamicClassLoader@22b4bba7 User.age = 11; out.println((int) ReflectUtil.getStaticFieldValue("age", uc1)); // 11 out.println((int) ReflectUtil.getStaticFieldValue("age", uc2)); // 10 public class User { public static int age = 10; }
  47. Class<?> uc1 = User.class; Class<?> uc2 = new DynamicClassLoader().load("com.zt.User"); out.println(uc1.getName());

    // com.zt.User out.println(uc2.getName()); // com.zt.User out.println(uc1.getClassLoader()); // sun.misc.Launcher$AppClassLoader@18b4aac2 out.println(uc2.getClassLoader()); // com.zt.DynamicClassLoader@22b4bba7 User.age = 11; out.println((int) ReflectUtil.getStaticFieldValue("age", uc1)); // 11 out.println((int) ReflectUtil.getStaticFieldValue("age", uc2)); // 10 public class User { public static int age = 10; }
  48. Class<?> uc1 = User.class; Class<?> uc2 = new DynamicClassLoader().load("com.zt.User"); out.println(uc1.getName());

    // com.zt.User out.println(uc2.getName()); // com.zt.User out.println(uc1.getClassLoader()); // sun.misc.Launcher$AppClassLoader@18b4aac2 out.println(uc2.getClassLoader()); // com.zt.DynamicClassLoader@22b4bba7 User.age = 11; out.println((int) ReflectUtil.getStaticFieldValue("age", uc1)); // 11 out.println((int) ReflectUtil.getStaticFieldValue("age", uc2)); // 10 public class User { public static int age = 10; }
  49. while(true) { Class<?> uc = new DynamicClassLoader().load("com.zt.User"); ReflectUtil.invokeStatic("getHobby", uc); }

    public class User { public Hobby getHobby() { return Basketball(); } }
  50. while(true) { Class<?> uc = new DynamicClassLoader().load("com.zt.User"); ReflectUtil.invokeStatic("getHobby", uc); }

    public class User { public Hobby getHobby() { return Basketball(); } }
  51. public static class Context { public HobbyService hobbyService = new

    HobbyService(); public void init() { hobbyService.user = new User(); anyService.initialize() } }
  52. public static class Context { public HobbyService hobbyService = new

    HobbyService(); public AnyService anyService = new AnyService(); public void init() { hobbyService.user = new User(); anyService.initialize() } }
  53. public static class Context { public HobbyService hobbyService = new

    HobbyService(); public AnyService anyService = new AnyService(); public void init() { hobbyService.user = new User(); anyService.initialize() } } while(true) { Class<?> c = new DynamicClassLoader().load("com.zt.Context"); Object context = c.newInstance(); ReflectUtil.invokeMethod("init", context); invokeService(context); }
  54. DynamicClassLoader Context class HobbyService class User class Context object HobbyService

    object User object Reloadable “region” Live thread
  55. None
  56. None
  57. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> DEMO

  58. None
  59. None
  60. None
  61. Java agents

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

    void premain(String args, Instrumentation inst) throws Exception { inst.addTransformer(new ClassFileTransformer { // here be dragons }); } }
  63. import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; public class Agent { public static

    void premain(String args, Instrumentation inst) throws Exception { inst.addTransformer(new ClassFileTransformer { // here be dragons }); } } META-INF/MANIFEST.MF Premain-Class: Agent
  64. import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.Instrumentation; public class Agent { public static

    void premain(String args, Instrumentation inst) throws Exception { inst.addTransformer(new ClassFileTransformer { // here be dragons }); } } $> java –javaagent:agent.jar application.Main META-INF/MANIFEST.MF Premain-Class: Agent
  65. ClassFileTransformer ClassA ClassA ClassA0 +field1 +field2 +field3 +method1 +method2 +method3

    +method1 +method2 +method3 +field1 +field2 +field3 +proxy_methods A thousand years of productivity: the JRebel story E. Kabanov, V. Vene, 2012
  66. ClassFileTransformer ClassA ClassA ClassA0 +field1 +field2 +field3 +method1 +method2 +method3

    +method1 +method2 +method3 +field1 +field2 +field3 +proxy_methods A thousand years of productivity: the JRebel story E. Kabanov, V. Vene, 2012
  67. None
  68. None
  69. HotSwap

  70. HotSwap Class loaders

  71. HotSwap Class loaders Java agents & instrumentation

  72. anton@zeroturnaround.com @antonarhipov