To inject or not to inject: CDI is the question

15,558
-1

Published on

This presentation shows you how to do dependency injection with CDI (Context & Dependency Injection)

Published in: Technology
2 Comments
24 Likes
Statistics
Notes
No Downloads
Views
Total Views
15,558
On Slideshare
0
From Embeds
0
Number of Embeds
6
Actions
Shares
0
Downloads
0
Comments
2
Likes
24
Embeds 0
No embeds

No notes for slide

To inject or not to inject: CDI is the question

  1. 1. To inject or not to inject : CDI is the question by a ntonio g oncalves
  2. 2. Welcome to a type-safe injection journey
  3. 3. Antonio Goncalves <ul><li>Freelance software architect
  4. 4. Author (Java EE 5 and Java EE 6)
  5. 5. JCP expert member (Java EE 6, Java EE 7)
  6. 6. Co-leader of the Paris JUG
  7. 7. Les Cast Codeurs podcast
  8. 8. Java Champion </li></ul>
  9. 9. <ul>Summary </ul><ul><li>IoC
  10. 10. Dependency Injection
  11. 11. @Inject & CDI
  12. 12. And that's it </li></ul>
  13. 13. Inversion of control <ul><li>Term popilarised in 1998
  14. 14. The control of : </li><ul><li>dependency resolution (DI)
  15. 15. lifecycle
  16. 16. configuration </li></ul><li>Is given to an external component (eg. container)
  17. 17. ...not the component itself
  18. 18. It brings loose coupling </li></ul>
  19. 19. Own deps Own config Own lifecycle Dependencies injected Config injected Lifecycle Managed from outside
  20. 20. Own deps Own config Own lifecycle Dependencies injected Config injected Lifecycle Managed from outside
  21. 21. Own deps Own config Own lifecycle Dependencies injected Config injected Lifecycle Managed from outside
  22. 22. Example of dependency
  23. 23. The good old new public class ItemService { private IsbnGenerator isbnGenerator ; public ItemService() { this. isbnGenerator = new IsbnGenerator() ; } public Book createBook(Book book) { ... book.setIsbn( isbnGenerator .generateNumber()); } }
  24. 24. What's wrong with that ? <ul><li>Strong coupling </li><ul><li>Impossible to change implementations
  25. 25. Impossible to MOCK if needed </li></ul><li>Lifecycle done by the component </li><ul><li>Sometimes new() is not enough
  26. 26. Creating an instance, opening, closing </li></ul></ul>
  27. 27. <ul>That's why we need DI </ul><ul><li>Design pattern (coined by Martin Fowler)
  28. 28. Decouples dependent components </li><ul><li>Loose coupling </li></ul><li>Hollywood Principle </li><ul><li>&quot;don’t call us, we’ll call you!&quot; </li></ul></ul>
  29. 29. How to choose implementation?
  30. 30. Constructor (or setter) injection public class ItemService { private NumberGenerator numberGenerator ; public ItemService(NumberGenerator numberGenerator ) { this.numberGenerator = numberGenerator ; } public Book createBook(Book book) { ... book.setIsbn( numberGenerator .generateNumber()); } }
  31. 31. With the good old new again // With constructor injection ItemService itemService = new ItemService( new IsbnGenerator() ); ItemService itemService = new ItemService( new IssnGenerator() ); // With setter injection ItemService itemService = new ItemService(); itemService.setNumberGenerator( new IsbnGenerator() ); itemService.setNumberGenerator( new IssnGenerator() );
  32. 32. Using factories <ul><li>Graph dependency can be complex
  33. 33. Factory design pattern (GoF)
  34. 34. Everywhere in Java </li><ul><li>java.util.Calendar#getInstance()
  35. 35. java.util.Arrays#asList()
  36. 36. java.sql.DriverManager#getConnection()
  37. 37. java.lang.Class#newInstance()
  38. 38. java.lang.Integer#valueOf() </li></ul></ul>
  39. 39. With a Factory public class ItemServiceFactory { public ItemService newIsbnGenerator() { return new ItemService( new IsbnGenerator() ); } public ItemService newIssnGenerator() { return new ItemService( new IssnGenerator() ); } } // Client ItemService itemService = new ItemServiceFactory(). newIsbnGenerator ();
  40. 40. Another pattern: Service Locator <ul><li>J2EE Design pattern
  41. 41. Used to find services
  42. 42. May reside in the same application, machine or network
  43. 43. JNDI is a perfect service locator </li></ul>ItemService itemService = new ServiceLocator() .get(” IsbnGeneratorService ”);
  44. 44. All that is constructing by hand // new() public ItemService() { this. isbnGenerator = new IsbnGenerator() ; } // Factory ItemService itemService = new ItemServiceFactory(). newIsbnGenerator (); // Service locator ItemService itemService = new ServiceLocator() .get(” IsbnGeneratorService ”);
  45. 45. Give control to an injector <ul><li>Injector aka container aka provider
  46. 46. Creating, assembling and wiring done by an external framework </li></ul>with Provides
  47. 47. Dependency injector <ul><li>Apache Avalon
  48. 48. Spring framework
  49. 49. Pico container
  50. 50. Nano container
  51. 51. Apache Hivemind
  52. 52. Seam
  53. 53. Google Guice
  54. 54. Contexts and Dependency Injection (CDI) </li></ul>
  55. 55. A bit of history May 1998 Project JPE Dec 1999 J2EE 1.2 Servlet/JSP EJB JMS RMI/IIOP Sept 2001 J2EE 1.3 CMP JCA Nov 2003 J2EE 1.4 WS Management Deployment May 2006 Java EE 5 Annotations EJB 3 JPA 1.0 WS-* JSF Q4 2009 Java EE 6 EJB 3.1 JPA 2.0 Servlet 3.0 JSF 2.0 JAX-RS 1.1 CDI 1.0 @Inject Bean Validat° Web Profile Managed Bean Resource injection Dependency injection
  56. 56. Resource injection in EE 5 <ul><li>Only inject container resources </li><ul><li>EJBs, entity manager, datasources, JMS factories & destinations </li></ul><li>To certain components </li><ul><li>EJBs, servlets, JSF managed beans </li></ul><li>Several annotations </li><ul><li>@Resource , @PersistenceContext , @PersistenceUnit , @EJB & @WebServiceRef </li></ul><li>No POJOs </li></ul>
  57. 57. Dependency injection in EE 6 <ul><li>Two seperate specifications </li><ul><li>Context & Dependency Injection (CDI) JSR 299
  58. 58. DI (aka @Inject) JSR 330 </li></ul><li>Bean container for Java EE
  59. 59. … and even outside Java EE </li></ul>
  60. 60. EE 5 resource injection @EJB @EJB @EJB @Resource @PersistenceContext
  61. 61. EE 6 dependency injection @Inject @Inject @Inject @Inject @Inject @Inject @Inject @Resource @PersistenceContext @Inject
  62. 62. 2 specs to archieve it <ul><li>DI (@Inject)
  63. 63. JSR 330
  64. 64. javax.inject
  65. 65. @Inject
  66. 66. @Named
  67. 67. @Singleton
  68. 68. @Qualifier
  69. 69. @Scope </li></ul><ul><li>CDI
  70. 70. JSR 299
  71. 71. javax.enterprise.context
  72. 72. Alternatives
  73. 73. Producers
  74. 74. Scopes & context
  75. 75. Stereotypes
  76. 76. Decorators, Events
  77. 77. Extensions </li></ul>
  78. 78. Injection with @Inject
  79. 79. @Inject @WebServlet(urlPatterns = &quot;/itemServlet&quot;) public class ItemServlet extends HttpServlet { @Inject private IsbnGenerator numberGenerator; ... book.setIsbn( isbnGenerator.generateNumber() ); } public class IsbnGenerator { public String generateNumber () { return &quot;13-84356-&quot; + nextNumber()); } } Injection point POJO Servlet
  80. 80. What's needed to make it work ? <ul><li>A container
  81. 81. CDI
  82. 82. An empty beans.xml file </li><ul><li>META-INF
  83. 83. WEB-INF </li></ul></ul>
  84. 84. @Inject @WebServlet(urlPatterns = &quot;/itemServlet&quot;) public class ItemServlet extends HttpServlet { @Inject private IsbnGenerator numberGenerator; ... book.setIsbn(isbnGenerator.generateNumber()); } public class IsbnGenerator { public String generateNumber () { return &quot;13-84356-&quot; + nextNumber()); } }
  85. 85. @Default @Inject @WebServlet(urlPatterns = &quot;/itemServlet&quot;) public class ItemServlet extends HttpServlet { @Inject @Default private IsbnGenerator numberGenerator; ... book.setIsbn(isbnGenerator.generateNumber()); } @Default public class IsbnGenerator { public String generateNumber () { return &quot;13-84356-&quot; + nextNumber()); } } Every bean has a @Default qualifier Every injection point has a @Default qualifier
  86. 86. Use your own qualifier @WebServlet(urlPatterns = &quot;/itemServlet&quot;) public class ItemServlet extends HttpServlet { @Inject @MyOwnQualifier private IsbnGenerator numberGenerator; ... book.setIsbn(isbnGenerator.generateNumber()); } @MyOwnQualifier public class IsbnGenerator { public String generateNumber () { return &quot;13-84356-&quot; + nextNumber()); } }
  87. 87. @MyOwnQualifier @Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD, PARAMETER}) public @interface MyOwnQualifier { }
  88. 88. Ambiguous injection
  89. 89. Non ambiguous injection
  90. 90. Defining the qualifiers @Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD, PARAMETER}) public @interface EightDigits { } @Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD, PARAMETER}) public @interface ThirteenDigits { }
  91. 91. Defining the beans @EightDigits public class IssnGenerator implements NumberGenerator { public String generateNumber() { return &quot;8-&quot; + nextNumber(); } } @ThirteenDigits public class IsbnGenerator implements NumberGenerator { public String generateNumber() { return &quot;13-84356-&quot; + nextNumber(); } }
  92. 92. Injection points @Path (&quot;/items&quot;) @ManagedBean public class ItemRestService { @Inject @EightDigits private NumberGenerator numberGenerator; ... } @WebServlet (urlPatterns = &quot;/itemServlet&quot;) public class ItemServlet extends HttpServlet { @Inject @ThirteenDigits private NumberGenerator numberGenerator; ... } Strong typing No strings Loose coupling No reference to the implementation
  93. 93. From XML hell to qualifier hell <ul><li>What if you need many qualifiers ?
  94. 94. 13, 8 digits but also 3, 7, 16, 19, 22, 26...
  95. 95. Use qualifiers with enumerations </li></ul>
  96. 96. Defining the qualifier & enum @Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD, PARAMETER}) public @interface NumberOfDigits { Digits value(); } public enum Digits { TWO, EIGHT, TEN, THIRTEEN }
  97. 97. Defining the beans @NumberOfDigits(Digits.EIGHT) public class IssnGenerator implements NumberGenerator { public String generateNumber() { return &quot;8-&quot; + nextNumber(); } } @NumberOfDigits(Digits.THIRTEEN) public class IsbnGenerator implements NumberGenerator { public String generateNumber() { return &quot;13-84356-&quot; + nextNumber(); } }
  98. 98. Injection points @Path(&quot;/items&quot;) @ManagedBean public class ItemRestService { @Inject @NumberOfDigits(Digits.EIGHT) private NumberGenerator numberGenerator; ... } @WebServlet(urlPatterns = &quot;/itemServlet&quot;) public class ItemServlet extends HttpServlet { @Inject @NumberOfDigits(Digits.THIRTEEN) private NumberGenerator numberGenerator; ... }
  99. 99. Different injection points <ul><li>Field
  100. 100. Constructor
  101. 101. Setter </li></ul>
  102. 102. Field injection @WebServlet(urlPatterns = &quot;/itemServlet&quot;) public class ItemServlet extends HttpServlet { @Inject @ThirteenDigits private NumberGenerator numberGenerator; @Inject private ItemEJB itemEJB; ... }
  103. 103. Constructor injection @WebServlet(urlPatterns = &quot;/itemServlet&quot;) public class ItemServlet extends HttpServlet { private NumberGenerator numberGenerator; private ItemEJB itemEJB; @Inject public ItemServlet( @ThirteenDigits NumberGenerator numberGenerator, ItemEJB itemEJB) { this.numberGenerator = numberGenerator; this.itemEJB = itemEJB; } ... }
  104. 104. Setter injection @WebServlet(urlPatterns = &quot;/itemServlet&quot;) public class ItemServlet extends HttpServlet { private NumberGenerator numberGenerator; private ItemEJB itemEJB; @Inject public void setNumberGenerator( @ThirteenDigits NumberGenerator numberGenerator) { this.numberGenerator = numberGenerator; } @Inject public void setItemEJB(ItemEJB itemEJB) { this.itemEJB = itemEJB; } }
  105. 105. Differences <ul><li>Field
  106. 106. Constructor </li><ul><li>only one constructor injection point
  107. 107. add logic to the constructor </li></ul><li>Setter </li><ul><li>add logic to the constructor </li></ul><li>Remember : the container is the one calling the constructor or the setters </li></ul>
  108. 108. Have you seen any XML so far ?
  109. 109. Alternatives <ul><li>Define an alternative implementation
  110. 110. Vary at deployment time
  111. 111. By default, alternative beans are disabled
  112. 112. Enable them with beans.xml file </li></ul>
  113. 113. Alternative to @ThirteenDigits @Alternative @ThirteenDigits public class MockGenerator implements NumberGenerator { public String generateNumber() { return &quot;MOCK-&quot; + nextNumber(); } }
  114. 114. Alternative to both @Alternative @ThirteenDigits @EightDigits public class MockGenerator implements NumberGenerator { public String generateNumber() { return &quot;MOCK-&quot; + nextNumber(); } } @Inject @ThirteenDigits private NumberGenerator numberGenerator;
  115. 115. beans.xml <?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?> <beans xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot; xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xsi:schemaLocation=&quot; http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd&quot;> <alternatives> <class>org.agoncal.cdi.MockGenerator</class> </alternatives> </beans>
  116. 116. Does this look too verbose ? @Alternative @ThirteenDigits @EightDigits public class MockGenerator implements NumberGenerator { public String generateNumber() { return &quot;MOCK-&quot; + nextNumber(); } }
  117. 117. Use stereotypes @MyMock public class MockGenerator implements NumberGenerator { public String generateNumber() { return &quot;MOCK-&quot; + nextNumber(); } } @Stereotype @Retention(RUNTIME) @Target(TYPE) @Alternative @ThirteenDigits @EightDigits public @interface MyMock {}
  118. 118. Stereotypes <ul><li>Models a common role in your application
  119. 119. You can think of a pattern </li><ul><li>Modeling recurring concerns </li></ul><li>Stereotypes may declare other stereotypes
  120. 120. Built-in stereotypes in CDI </li><ul><li>@Model as a replacement of JSF managed beans </li></ul></ul>
  121. 121. So, we only inject beans ?
  122. 122. Producers <ul><li>Producers are a source for objects to be injected </li><ul><li>these objects are not required to be beans </li></ul><li>For example, producer methods let us: </li><ul><li>expose a JPA entity as a bean
  123. 123. expose any JDK class as a bean </li></ul></ul>
  124. 124. Produce an injectable String public class PrefixGenerator { @Produces @ThirteenDigits public String getIsbnPrefix() { return &quot;13-84356&quot;; } @Produces @EightDigits public String getIssnPrefix() { return &quot;8&quot;; } }
  125. 125. Inject the produced String @ThirteenDigits public class IsbnGenerator implements NumberGenerator { @Inject @ThirteenDigits private String prefix ; public String generateNumber() { return prefix + &quot;-&quot; + nextNumber(); } } Bean String
  126. 126. Java EE integration <ul><li>Built-in beans in EE : </li><ul><li>current JTA UserTransaction
  127. 127. a Principal for the current caller identity
  128. 128. default Bean Validation ValidationFactory
  129. 129. a Validator for the ValidationFactory </li></ul><li>For other beans, use producers </li></ul>
  130. 130. Produce an EntityManager public class DatabaseProducer { @Produces @PersistenceContext(unitName = &quot;cdiPU&quot;) @BookStoreDatabase private EntityManager em; } @Stateless public class ItemEJB { @Inject @BookStoreDatabase private EntityManager em; ... }
  131. 131. Produce a FacesContext public class FacesContextProducer { @Produces @RequestScoped FacesContext getFacesContext() { return FacesContext.getCurrentInstance(); } }
  132. 132. Produce JMS endpoints public class OrderResources { @Resource (name = &quot;jms/ConnectionFactory&quot;) private ConnectionFactory connectionFactory; @Resource (name = &quot;jms/OrderQueue&quot;) private Queue orderQueue; @Produces @OrderConnection public Connection createOrderConnection() { return connectionFactory.createConnection(); } @Produces @OrderSession public Session createOrderSession( @OrderConnection Connection conn){ return conn.createSession(true, Session.AUTO_ACKNOWLEDGE); } ... }
  133. 133. Consume JMS endpoints @Inject @OrderSession QueueSession orderSession; public void sendMessage() { MapMessage msg = orderSession .createMapMessage(); msg.setLong(&quot;orderId&quot;, order.getId()); ... producer.send(msg); }
  134. 134. Can I use all that from a JSF page ?
  135. 135. @Named <ul><li>Reference a bean from the Expression Language
  136. 136. Gives it a name (a String)
  137. 137. Most commonly from a JSF view
  138. 138. Non type safe dependency injection
  139. 139. Any bean can be named
  140. 140. Do we still need JSF managed beans ? </li></ul>
  141. 141. Default name @Named public class IsbnGenerator { public String generateNumber() { return &quot;13-84356-&quot; + nextNumber(); } } <h:outputLabel value=&quot; #{isbnGenerator.generateNumber} &quot;/>
  142. 142. A different name @Named(&quot; generator &quot;) public class IsbnGenerator { public String generateNumber() { return &quot;13-84356-&quot; + nextNumber(); } } <h:outputLabel value=&quot;#{ generator .generateNumber}&quot;/>
  143. 143. Mix a producer and a default name public class IsbnGenerator { @Produces @Named public String generateNumber() { return &quot;13-84356-&quot; + nextNumber(); } } <h:outputLabel value=&quot;#{ generateNumber }&quot;/>
  144. 144. Mix a producer and a name public class IsbnGenerator { @Produces @Named(&quot; isbnNumber &quot;) public String generateNumber() { return &quot;13-84356-&quot; + nextNumber(); } } <h:outputLabel value=&quot;#{ isbnNumber }&quot;/>
  145. 145. How can I have all these goodies ?
  146. 146. CDI is not just about Java EE 6 <ul><li>CDI comes for free in Java EE 6 & Web Profile 1.0
  147. 147. Bootstrap CDI in several environments
  148. 148. Not standard (yet) </li><ul><li>Java SE
  149. 149. Tomcat 6.x / 7.x
  150. 150. Jetty 6.X / 7.x </li></ul><li>Doesn't work ? </li><ul><li>Application client container (ACC)
  151. 151. Spring 3.x </li></ul></ul>
  152. 152. Doesn't work with Spring? <ul><li>Spring 3.x
  153. 153. Only DI is supported (JSR 330)
  154. 154. Not CDI (JSR 299)
  155. 155. You can replace @Autowired with @Inject </li></ul>
  156. 156. CDI implementations <ul><li>Weld (JBoss)
  157. 157. Open WebBeans (Apache)
  158. 158. CanDI (Caucho) </li></ul>
  159. 159. CDI is not just about DI <ul><li>Scopes & context
  160. 160. Decorators
  161. 161. Events
  162. 162. Extensions </li><ul><li>Finally makes the EE platform extendable </li></ul></ul>
  163. 163. What makes CDI Unique ? <ul><li>It's standard
  164. 164. It's type-safe
  165. 165. It's extensible </li></ul>
  166. 166. And what about the future ? <ul><li>Java EE 7
  167. 167. CDI 1.1 is on the way </li><ul><li>Embedded mode outside Java EE container
  168. 168. Static injection
  169. 169. Better support for CDI in certain EE components
  170. 170. Application lifecycle events
  171. 171. ... </li></ul></ul>
  172. 172. Java EE 6 <ul><li>A book </li><ul><li>450 pages about Java EE 6
  173. 173. Second edition
  174. 174. Covers most specs </li></ul><li>A training </li><ul><li>3 days
  175. 175. Most specs
  176. 176. Hands on labs
  177. 177. Contact me </li></ul></ul>
  178. 178. Thanks www.antoniogoncalves.org [email_address] @agoncal @lescastcodeurs
  179. 179. Creative Commons <ul><li>Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work).
  180. 180. Noncommercial — You may not use this work for commercial purposes.
  181. 181. Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under the same or similar license to this one. </li></ul>

×