Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

JavaOne 2017 - The hitchhiker’s guide to Java class reloading

160 views

Published on

In Java, a typical workflow involves restarting the application with (almost) every class change. For some applications, it is not a problem at all; for others, it is a disaster, from HotSwap to agent-based reloading. This session takes a look at the options available for Java class reloading. There are plenty of tools you can use for this task: rely on standard JVM HotSwap, redesign your application to rely on dynamic class loaders, comprehend the Zen of OSGi, or integrate a reloading agent. Every option has its own drawbacks and benefits, and the presentation takes a deep dive into the subject. Come get a better understanding of class reloading technologies and become a more productive Java developer.

Published in: Software
  • Be the first to comment

  • Be the first to like this

JavaOne 2017 - The hitchhiker’s guide to Java class reloading

  1. 1. The hitchhiker’s guide to Java class reloading @antonarhipov
  2. 2. whoami Anton Arhipov @antonarhipov
  3. 3. whoami Anton Arhipov @antonarhipov
  4. 4. https://zeroturnaround.com/rebellabs/java-ee-productivity-report-2011/ 10% 20% 30% 0.5 1 2 3 4 5 6 7 8 10+ minutes
  5. 5. 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
  6. 6. 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
  7. 7. The problem: where did the time go?
  8. 8. The problem: where did the time go? 1-30 sec Container startup time
  9. 9. The problem: where did the time go? 1-30 sec Container startup time ~3 min 30 min1 s Application deployment
  10. 10. The problem: where did the time go? 1-30 sec Container startup time ~3 min 30 min1 s Application deployment ~1 min Navigation
  11. 11. Technical solutions
  12. 12. Technical solutions HotSwap
  13. 13. Technical solutions HotSwap Class loaders
  14. 14. Technical solutions HotSwap Class loaders Java agents & instrumentation
  15. 15. Technical solutions HotSwap Class loaders Java agents & instrumentation
  16. 16. hotswapEST. 2001
  17. 17. HOW ABOUT… refactoring?
  18. 18. JDB
  19. 19. 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
  20. 20. 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
  21. 21. 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
  22. 22. 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
  23. 23. 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 Limited to individual statements
  24. 24. What if… hotswap++
  25. 25. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L. Stadler. 2010
  26. 26. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L. Stadler. 2010 Statements
  27. 27. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L. Stadler. 2010 Statements Methods
  28. 28. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L. Stadler. 2010 Statements Methods Fields
  29. 29. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L. Stadler. 2010 Statements Methods Fields Hierarchy
  30. 30. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L. Stadler. 2010 Statements Methods Fields Hierarchy
  31. 31. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L. Stadler. 2010 Statements Methods Fields Hierarchy + + + Binary-compatible
  32. 32. Dynamic Code Evolution for Java T. Würthinger, C. Wimmer, L. Stadler. 2010 Statements Methods Fields Hierarchy + + + x x x Binary-compatible Binary-incompatible
  33. 33. Classloaders
  34. 34. 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; }
  35. 35. 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; }
  36. 36. 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; }
  37. 37. 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; }
  38. 38. 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; }
  39. 39. while(true) { Class<?> uc = new DynamicClassLoader().load("com.zt.User"); ReflectUtil.invokeStatic("getHobby", uc); } public class User { public Hobby getHobby() { return Basketball(); } }
  40. 40. while(true) { Class<?> uc = new DynamicClassLoader().load("com.zt.User"); ReflectUtil.invokeStatic("getHobby", uc); } public class User { public Hobby getHobby() { return Basketball(); } }
  41. 41. while(true) { Class<?> uc = new DynamicClassLoader().load("com.zt.User"); ReflectUtil.invokeStatic("getHobby", uc); } public class User { public Hobby getHobby() { return Basketball(); } } Assume there is a trigger / event
  42. 42. public static class Context { public HobbyService hobbyService = new HobbyService(); public void init() { hobbyService.user = new User(); anyService.initialize() } }
  43. 43. public static class Context { public HobbyService hobbyService = new HobbyService(); public AnyService anyService = new AnyService(); public void init() { hobbyService.user = new User(); anyService.initialize() } }
  44. 44. 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); }
  45. 45. DynamicClassLoader Context class HobbyService class User class Context object HobbyService object User object Reloadable “region” Live thread
  46. 46. <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> </dependency> DEMO
  47. 47. Java agents
  48. 48. 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 }); } }
  49. 49. 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
  50. 50. 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
  51. 51. 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
  52. 52. 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
  53. 53. What did we learn today?
  54. 54. What did we learn today? HotSwap - a feature of your JVM, not IDE!
  55. 55. What did we learn today? HotSwap - a feature of your JVM, not IDE! Class loaders - easy to implement, but limited
  56. 56. What did we learn today? HotSwap - a feature of your JVM, not IDE! Class loaders - easy to implement, but limited Java agents & instrumentation - very tricky!
  57. 57. anton@zeroturnaround.com @antonarhipov slideshare.net/arhan

×