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

JEEConf 2017 - The hitchhiker's guide to Java class reloading

JEEConf 2017 - The hitchhiker's guide to Java class reloading

1bc80e2eee2adeaa8bb577798d92e9d0?s=128

Anton Arhipov

May 26, 2017
Tweet

Transcript

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

  2. whoami Anton Arhipov @antonarhipov

  3. whoami Anton Arhipov @antonarhipov

  4. None
  5. None
  6. HotSwap

  7. HotSwap Class loaders

  8. HotSwap Class loaders Java agents & instrumentation

  9. hotswap EST. 2001

  10. None
  11. None
  12. None
  13. None
  14. None
  15. None
  16. None
  17. None
  18. None
  19. HOW ABOUT… refactoring?

  20. None
  21. None
  22. None
  23. JDB

  24. 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
  25. 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
  26. 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
  27. 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
  28. What if… hotswap++

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

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

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

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

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

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

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

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

    Stadler. 2010 Statements Methods Fields Hierarchy + + + x x x Binary-compatible Binary-incompatible
  37. None
  38. Classloaders

  39. 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; }
  40. 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; }
  41. 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; }
  42. 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; }
  43. 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; }
  44. while(true) { Class<?> uc = new DynamicClassLoader().load("com.zt.User"); ReflectUtil.invokeStatic("getHobby", uc); }

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

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

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

    HobbyService(); public AnyService anyService = new AnyService(); public void init() { hobbyService.user = new User(); anyService.initialize() } }
  48. 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); }
  49. DynamicClassLoader Context class HobbyService class User class Context object HobbyService

    object User object Live thread
  50. None
  51. None
  52. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> DEMO

  53. None
  54. None
  55. None
  56. Java agents

  57. None
  58. 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
  59. 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
  60. DEMO

  61. None
  62. HotSwap

  63. HotSwap Class loaders

  64. HotSwap Class loaders Java agents & instrumentation

  65. anton@zeroturnaround.com @antonarhipov