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.

Invoke dynamite in Java EE with invoke dynamic

1,902 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

×