Invoke dynamite in Java EE with invoke dynamic

1,577 views
1,409 views

Published on

This talk expose how the JDK 7 InvokeDynamic feature could be used to replace proxies in Java EE

Published in: Software, Technology, Education

Invoke dynamite in Java EE with invoke dynamic

  1. 1. Let’s Invoke Dynamite in Java EE with InvokeDynamic Antoine Sabot-Durand Senior Software Engineer Red Hat @antoine_sd / #IndyEE http://www.revistashqiptare.com/wp-content/uploads/2013/10/prishje-me-C4.jpg
  2. 2. Antoine Sabot-Durand • Senior Software Engineer @Red Hat ! • Java & OSS : • CDI co-spec lead • CDI community development • Tech Lead on Agorava ! • @antoine_sd 2
  3. 3. My support team
  4. 4. Agenda • Back in time • Proxies - the sweet poison • The Invoke Dynamic antidote • @Inject Demo • To be done • Q&A 4
  5. 5. Disclaimer 5 I’M NOT AN INVOKEDYNAMIC, BYTECODE OR ASM EXPERT, ONLY A USER. FOR ADVANCED QUESTION, ASK THOSE GUYS
  6. 6. Back in time https://www.flickr.com/photos/revolweb/3985108034
  7. 7. public void ship (String productId, String orderId, int quantity) {
 try {
 makeConnection();
 con.setAutoCommit(false);
 updateOrderItem(productId, orderId);
 updateInventory(productId, quantity);
 con.commit();
 } catch (Exception ex) {
 try {
 con.rollback();
 throw new EJBException("Transaction failed: " + ex.getMessage());
 } catch (SQLException sqx) {
 throw new EJBException("Rollback failed: " + sqx.getMessage());
 }
 } finally {
 releaseConnection();
 }
 } Long, long time ago… 7 ALL TRANSVERSE CODE HAD TO BE DUPLICATED EVERYWHERE
  8. 8. Then AOP was invented • All cross-cutting concerns was extracted in one place • Initiated at Xerox PARC in 1996 • AspectJ is released in 2001. • Spring is released in 2004. • Java EE adopted it in 2006 with Java EE 5 • In Java you can do AOP with code weaving (Open JPA) or theoretically with reflexion • But the most popular tools to do AOP are… 8 @Transactional public void ship (String productId, String orderId, int quantity) {
 updateOrderItem(productId, orderId);
 updateInventory(productId, quantity);
 }
  9. 9. Proxies https://www.flickr.com/photos/mhall209/3411159477
  10. 10. Proxies https://www.flickr.com/photos/hape_gera/3281625420/sizes/o/in/photostream/
  11. 11. What’s a proxy • At the beginning it’s a design pattern in OOP : ! ! ! • It can be implemented in static code with an interface and a « client » class wrapping another class doing the actual work • In Java EE implementations the proxy class is dynamically created at runtime 11 « proxy provides a surrogate or a placeholder for another object to control access to it. » Sincerely yours, The Gang Of Four
  12. 12. private Class<T> createProxyClass(String proxyClassName) throws Exception {
 ArraySet<Class<?>> specialInterfaces = new ArraySet<Class<?>>();
 addAdditionalInterfaces(specialInterfaces);
 ClassFile proxyClassType = null;
 if (getBeanType().isInterface()) {
 proxyClassType = new ClassFile(proxyClassName, Object.class.getName());
 proxyClassType.addInterface(getBeanType().getName());
 } else {
 proxyClassType = new ClassFile(proxyClassName, getBeanType().getName());
 }
 for (Class<?> clazz : additionalInterfaces) {
 proxyClassType.addInterface(clazz.getName());
 }
 List<DeferredBytecode> initialValueBytecode = new ArrayList<DeferredBytecode>();
 
 ClassMethod staticConstructor = proxyClassType.addMethod(AccessFlag.PUBLIC, "<clinit>", "V");
 
 addFields(proxyClassType, initialValueBytecode);
 addConstructors(proxyClassType, initialValueBytecode);
 addMethods(proxyClassType, staticConstructor);
 
 staticConstructor.getCodeAttribute().returnInstruction();
 
 Class<T> proxyClass = cast(ClassFileUtils.toClass(proxyClassType, classLoader, domain));
 BeanLogger.LOG.createdProxyClass(proxyClass, Arrays.toString(proxyClass.getInterfaces()));
 return proxyClass;
 } Example from Weld 12
  13. 13. What are the issues with proxies • Need a engine for object creation :The container proliferation • Make a lot of boilerplate code in frameworks • Long and weird stack traces • Two objects when one could enough • JIT compiler cannot optimize this runtime generated code • Costly in CPU and memory • And strange impact on specification… 13
  14. 14. Proxies tautology http://www.rcgroups.com/forums/attachment.php?attachmentid=4004213
  15. 15. Meet Indy http://commons.wikimedia.org/wiki/File:Bullwhip_and_IJ_hat.jpg
  16. 16. InvokeDynamic the good parts • Is a JDK built-in solution to do linking at runtime • Introduced in Java 7 with JSR 292 • Designed to implement dynamic language on JVM (JRuby, Groovy, Golo, Nashorn) • Better than standard reflection • Type Safe and not « interpreted » • Better than standard bytecode manipulation • Nearly everything is in JDK package java.lang.invoke • Better than proxies • Resolve all proxies issues 16
  17. 17. InvokeDynamic the WTF part There’s no java instruction to produce InvokeDynamic Bytecode instruction. ! So we have to do byte code manipulation to add it 17 http://upload.wikimedia.org/wikipedia/commons/1/14/Rubber_Duck_(8374802487).jpg
  18. 18. Indy : the usual suspects • The InvokeDynamic instruction • It contains a reference to the bootstrap method • The Boostrap method which does the dynamic linking • Called once for a given indy instruction • Return a Callsite containing the actual code • The CallSite Object • Contains the handle to the method to call • Can be be mutable (we won’t show that here) • The MethodeHandle • Handle to the final method 18
  19. 19. http://cache.reelz.com/assets/content/repFrame/65555/indiana.jpg Invoke dynamic call Bootstrap method Callsite MethodHandle
  20. 20. Demo
  21. 21. Proof by stacktrace 21 Code and Readme are here : https://github.com/antoinesd/weld-invokedynamic
  22. 22. @ApplicationScoped
 public class SecondBean {
 
 @Inject
 FirstBean bean;
 
 public void doSservice() {
 System.out.println("Service in SecondBean calling firstBean");
 bean.doSomeWork();
 
 }
 
 @PostConstruct
 public void init() {
 System.out.println("Contructing Second Bean");
 }
 
 } SecondBean Source 22
  23. 23. public class org/jboss/weld/test/SecondBean {! ! @Ljavax/enterprise/context/ApplicationScoped;()! ! Lorg/jboss/weld/test/FirstBean; bean! @Ljavax/inject/Inject;()! ! public doSservice()V! L0! LINENUMBER 18 L0! GETSTATIC java/lang/System.out : Ljava/io/PrintStream;! LDC "Service in SecondBean calling firstBean"! INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V! L1! LINENUMBER 19 L1! ALOAD 0! GETFIELD org/jboss/weld/test/SecondBean.bean : Lorg/jboss/weld/test/FirstBean;! INVOKEVIRTUAL org/jboss/weld/test/FirstBean.doSomeWork ()V! L2! LINENUMBER 21 L2! RETURN! } SecondBean standard bytecode 23
  24. 24. public class org/jboss/weld/test/SecondBean {! ! @Ljavax/enterprise/context/ApplicationScoped;()! ! Lorg/jboss/weld/test/FirstBean; bean! @Ljavax/inject/Inject;()! ! public doSservice()V! L0! LINENUMBER 18 L0! GETSTATIC java/lang/System.out : Ljava/io/PrintStream;! LDC "Service in SecondBean calling firstBean"! INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V! L1! LINENUMBER 19 L1! ALOAD 0! INVOKEDYNAMIC bean(Lorg/jboss/weld/test/SecondBean;)Lorg/jboss/weld/test/FirstBean; [! // handle kind 0x6 : INVOKESTATIC! org/jboss/weld/invokedynamic/Bootstraper.bootstrapGetBean(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/ String;Ljava/lang/invoke/MethodType;Ljava/lang/String;)Ljava/lang/invoke/CallSite;! // arguments:! "bean"! ]! INVOKEDYNAMIC doSomeWork(Lorg/jboss/weld/test/FirstBean;)V [! // handle kind 0x6 : INVOKESTATIC! org/jboss/weld/invokedynamic/Bootstraper.bootstrapCallBeanMethod(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/ String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;! // arguments:! // handle kind 0x5 : INVOKEVIRTUAL! org/jboss/weld/test/FirstBean.doSomeWork()V, ! "bean"! ]! L2! LINENUMBER 21 L2! RETURN! } SecondBean Indy bytecode 24
  25. 25. To be done… • Implement @Inject on constructor and setter • Manage the use case of field containing bean without Injection Point • Add Indy to Instance<> methods • Implement interceptors • Implement decorators • Remove all proxies from Weld 25
  26. 26. Q&A

×