KEMBAR78
Introduction to cdi given at java one 2014 | PDF
INTRODUCTION TO CONTEXTS AND 
DEPENDENCY INJECTION (CDI) 
@antoine_sd
ANTOINE SABOT-DURAND 
• Senior Software Engineer @Red Hat 
• Java & OSS : 
• CDI co-spec lead 
• CDI community development 
• Tech Lead on Agorava 
• @antoine_sd
WHAT IS CDI ? 
• Java EE dependency injection standard 
• Strong typed and type safe 
• Context management 
• Observer pattern included (Event bus) 
• Highly extensible
A BIT OF HISTORY 
CDI 1.0 (Java EE 6) 
CDI 1.1 (Java EE 7) 
CDI 1.2 (1.1 MR) 
CDI 2.0 Starts 
Dec 2009 June 2013 Apr 2014 Sep 2014 
CDI 2.0 released 
Q1 2016
IMPLEMENTATIONS 
JBoss Weld (Reference Implementation) Apache Open WebBeans
CDI ACTIVATION 
• In CDI 1.0, you must add a beans.xml file to your archive 
• Since CDI 1.1, it’s activated by default: 
• All classes having a “bean defining annotation” become a bean 
• You can still use beans.xml file to activate CDI explicitly or 
deactivate it
THE CDI BEAN 
• In Java EE 6 and 7 everything is a Managed Bean 
• Managed beans are basic components 
• They are managed by the container 
• They all have a lifecycle 
• They can be intercepted (AOP) 
• They can be injected 
• Accessible from outside CDI code.
BASIC DEPENDENCY INJECTION 
@Inject
THIS IS A BEAN 
public class HelloService { 
public String hello() { 
return "Hello World!"; 
} 
}
DI IN CONSTRUCTOR 
public class MyBean { 
private HelloService service; 
@Inject 
public MyBean(HelloService service) { 
this.service = service; 
} 
}
DI IN SETTER 
public class MyBean { 
private HelloService service; 
@Inject 
public void setService(HelloService service) { 
this.service = service; 
} 
}
DI IN FIELD 
public class MyBean { 
@Inject 
private HelloService service; 
public void displayHello() { 
display(service.hello(); 
} 
}
NO TYPE ERASURE IN CDI 
public class MyBean { 
@Inject Service<User> userService; 
@Inject Service<Staff> staffService; 
} 
This works
USING QUALIFIERS TO DISTINGUISH 
BEANS OF THE SAME TYPE
2 SERVICE IMPLEMENTATIONS… 
public interface HelloService { 
public String hello(); 
} 
public class FrenchHelloService implements HelloService { 
public String hello() { 
return "Bonjour tout le monde!"; 
} 
} 
public class EnglishHelloService implements HelloService { 
public String hello() { 
return "Hello World!"; 
} 
}
…NEED QUALIFIERS… 
@Qualifier 
@Retention(RUNTIME) 
@Target({FIELD, TYPE, METHOD, PARAMETER}) 
public @interface French {} 
@Qualifier 
@Retention(RUNTIME) 
@Target({FIELD, TYPE, METHOD, PARAMETER}) 
public @interface English {}
…TO BE DISTINGUISHED. 
@French 
public class FrenchHelloService implements HelloService { 
public String hello() { 
return "Bonjour tout le monde!"; 
} 
} 
@English 
public class EnglishHelloService implements HelloService { 
public String hello() { 
return "Hello World!"; 
} 
}
QUALIFIED INJECTION POINTS 
public class MyBean { 
@Inject @French HelloService service; 
public void displayHello() { 
display( service.hello(); 
} 
} 
public class MyBean { 
@Inject @English HelloService service; 
public void displayHello() { 
display( service.hello(); 
} 
}
QUALIFIERS CAN HAVE MEMBERS 
@Qualifier 
@Retention(RUNTIME) 
@Target({FIELD, TYPE, METHOD, PARAMETER}) 
public @interface Language { 
Languages value(); 
@Nonbinding String description() default ""; 
public enum Languages { 
FRENCH, ENGLISH 
} 
}
QUALIFIERS WITH MEMBERS 1/2 
@Language(FRENCH) 
public class FrenchHelloService implements HelloService { 
public String hello() { 
return "Bonjour tout le monde!"; 
} 
} 
@Language(ENGLISH) 
public class EnglishHelloService implements HelloService { 
public String hello() { 
return "Hello World!"; 
} 
}
QUALIFIERS WITH MEMBERS 2/2 
public class MyBean { 
@Inject @Language(ENGLISH) HelloService service; 
public void displayHello() { 
display( service.hello(); 
} 
} 
public class MyBean { 
@Inject @Language(FRENCH) HelloService service; 
public void displayHello() { 
display( service.hello(); 
} 
}
MULTIPLE QUALIFIERS 
public class MyBean { 
@Inject @French 
HelloService service; 
} 
@French @Console @Secured 
public class FrenchHelloService implements HelloService { 
}
MULTIPLE QUALIFIERS 
public class MyBean { 
@Inject @French @Console 
HelloService service; 
} 
@French @Console @Secured 
public class FrenchHelloService implements HelloService { 
}
MULTIPLE QUALIFIERS 
public class MyBean { 
@Inject @French @Console @Secured 
HelloService service; 
} 
@French @Console @Secured 
public class FrenchHelloService implements HelloService { 
}
MULTIPLE QUALIFIERS 
public class MyBean { 
@Inject @French @Console @Secured 
HelloService service; 
} 
@French @Secured 
public class FrenchHelloService implements HelloService { 
}
RESERVED QUALIFIERS 
@Default 
@Any 
@Named
PROGRAMMATIC LOOKUP
SOMETIMES CALLED “LAZY INJECTION” 
public class MyBean { 
@Inject Instance<HelloService> service; 
public void displayHello() { 
display( service.get().hello() ); 
} 
}
CHECK BEAN EXISTENCE AT RUNTIME 
public class MyBean { 
@Inject Instance<HelloService> service; 
public void displayHello() { 
if (!service.isUnsatisfied()) { 
display( service.get().hello() ); 
} 
} 
}
INSTANCE<T> IS ITERABLE 
public interface Instance<T> extends Iterable<T>, Provider<T> { 
public Instance<T> select(Annotation... qualifiers); 
public <U extends T> Instance<U> select(Class<U> subtype, Annotation... qualifiers); 
public <U extends T> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers); 
public boolean isUnsatisfied(); 
public boolean isAmbiguous(); 
public void destroy(T instance); 
}
LOOP ON ALL BEANS OF A GIVEN TYPE 
public class MyBean { 
@Inject @Any Instance<HelloService> services; 
public void displayHello() { 
for (HelloService service : services) { 
display( service.hello() ); 
} 
} 
}
SELECT A QUALIFIER AT RUNTIME 
public class MyBean { 
@Inject @Any Instance<HelloService> services; 
public void displayHello() { 
display( 
service.select( 
new AnnotationLiteral()<French> {}) 
.get() ); 
} 
}
CONTEXTS
CONTEXTS MANAGE BEANS LIFECYCLE 
• They helps container to choose when a bean should be instantiated and destroyed 
• They enforce the fact that a given bean is a singleton for a given context 
• Built-in CDI contexts : 
• @Dependent (default) 
• @ApplicationScoped, @SessionScoped, @RequestScoped 
• @ConversationScoped 
• @Singleton 
• You can create your own scope
CHOOSING THE RIGHT CONTEXT 
@SessionScoped 
public class CartBean { 
public void addItem(Item item) { 
... 
} 
}
CHOOSING THE RIGHT CONTEXT 
@ApplicationScoped 
public class CartBean { 
public void addItem(Item item) { 
... 
} 
} 
FAIL !!!
CONVERSATION IS MANAGE BY DEV 
@ConversationScoped 
public class CartBean { 
public void addItem(Item item) { 
... 
} 
}
NEW CONTEXTS CAN BE CREATED 
@ThreadScoped 
public class CartBean { 
public void addItem(Item item) { 
... 
} 
}
PRODUCERS
CREATING BEAN FROM ANY CLASS 
@Produces 
public MyNonCDIClass myProducer() { 
return new MyNonCdiClass(); 
} 
... 
@Inject 
MyNonCDIClass bean;
PRODUCERS MAY HAVE A SCOPE 
@Produces 
@RequestScoped 
public FacesContext produceFacesContext() { 
return FacesContext.getCurrentInstance(); 
}
GETTING INFO FROM INJECTION POINT 
@Produces 
public Logger produceLog(InjectionPoint injectionPoint) { 
return Logger.getLogger(injectionPoint.getMember() 
.getDeclaringClass().getName()); 
}
REMEMBER : “NO TYPE ERASURE” 
@Produces 
public <K, V> Map<K, V> produceMap(InjectionPoint ip) { 
if (valueIsNumber(ip.getType())) { 
return new TreeMap<K, V>(); 
} 
return new HashMap<K, V>(); 
}
EVENTS
A NICE WAY TO ADD DECOUPLING 
public class FirstBean { 
@Inject Event<Post> postEvent; 
public void saveNewPost(Post myPost) { 
postEvent.fire(myPost); 
} 
} 
public class SecondBean { 
public void listenPost(@Observes Post post) { 
System.out.println("Received : " + evt.message()); 
} 
}
EVENTS CAN BE QUALIFIED 
public class FirstBean { 
@Inject Event<Post> postEvent; 
public void saveNewPost(Post myPost) { 
postEvent.select( 
new AnnotationLiteral()<French> {}).fire(myPost); 
} 
} 
public class SecondBean { 
// these 3 observers will be called 
public void listenFrPost(@Observes @French Post post) {} 
public void listenPost(@Observes Post post) {} 
public void listenObject(@Observes Object obj) {} 
// This one won’t be called 
public void listenEnPost(@Observes @English Post post) {} 
}
AS ALWAYS “NO TYPE ERASURE” 
public class SecondBean { 
// these observers will be resolved depending 
// on parameter in event payload type 
public void listenStrPost(@Observes Post<String> post) {} 
public void listenNumPost(@Observes Post<Number> post) {} 
}
SOME BUILT-IN EVENTS 
public class SecondBean { 
public void beginRequest(@Observes @Initialized(RequestScoped.class) 
ServletRequest req) {} 
public void endRequest(@Observes @Destroyed(RequestScoped.class) 
ServletRequest req) {} 
public void beginSession(@Observes @Initialized(SessionScoped.class) 
HttpSession session) {} 
public void endSession(@Observes @Destroyed(SessionScoped.class) 
HttpSession session) {} 
}
DECORATORS & INTERCEPTORS
A DECORATOR 
@Decorator 
@Priority(Interceptor.Priority.APPLICATION) 
public class HelloDecorator implements HelloService { 
// The decorated service may be restricted with qualifiers 
@Inject @Delegate HelloService service; 
public String hello() { 
return service.hello() + "-decorated"; 
} 
}
INTERCEPTOR BINDING… 
@InterceptorBinding 
@Target({METHOD, TYPE}) 
@Retention(RUNTIME) 
public @interface Loggable {}
…IS USED TO BIND AN INTERCEPTOR 
@Interceptor @Loggable 
@Priority(Interceptor.Priority.APPLICATION) 
public class LogInterceptor { 
@AroundInvoke 
public Object log(InvocationContext ic) throws Exception { 
System.out.println("Entering " + ic.getMethod().getName()); 
try { 
return ic.proceed(); 
} finally { 
System.out.println("Exiting " + ic.getMethod().getName()); 
} 
} 
}
IT CAN BE PUT ON CLASS OR METHOD 
@Loggable 
public class MyBean { 
@Inject HelloService service; 
public void displayHello() { 
display( service.hello(); 
} 
}
THAT’S ALL FOR BASIC CDI 
• If you want to learn advanced stuff come to : 
Going Farther with CDI 1.2 [CON5585] Monday 5:30pm 
• visit : http://cdi-spec.org 
• follow @cdispec and @antoine_sd on twitter 
• Questions ?

Introduction to cdi given at java one 2014

  • 1.
    INTRODUCTION TO CONTEXTSAND DEPENDENCY INJECTION (CDI) @antoine_sd
  • 2.
    ANTOINE SABOT-DURAND •Senior Software Engineer @Red Hat • Java & OSS : • CDI co-spec lead • CDI community development • Tech Lead on Agorava • @antoine_sd
  • 3.
    WHAT IS CDI? • Java EE dependency injection standard • Strong typed and type safe • Context management • Observer pattern included (Event bus) • Highly extensible
  • 4.
    A BIT OFHISTORY CDI 1.0 (Java EE 6) CDI 1.1 (Java EE 7) CDI 1.2 (1.1 MR) CDI 2.0 Starts Dec 2009 June 2013 Apr 2014 Sep 2014 CDI 2.0 released Q1 2016
  • 5.
    IMPLEMENTATIONS JBoss Weld(Reference Implementation) Apache Open WebBeans
  • 6.
    CDI ACTIVATION •In CDI 1.0, you must add a beans.xml file to your archive • Since CDI 1.1, it’s activated by default: • All classes having a “bean defining annotation” become a bean • You can still use beans.xml file to activate CDI explicitly or deactivate it
  • 7.
    THE CDI BEAN • In Java EE 6 and 7 everything is a Managed Bean • Managed beans are basic components • They are managed by the container • They all have a lifecycle • They can be intercepted (AOP) • They can be injected • Accessible from outside CDI code.
  • 8.
  • 9.
    THIS IS ABEAN public class HelloService { public String hello() { return "Hello World!"; } }
  • 10.
    DI IN CONSTRUCTOR public class MyBean { private HelloService service; @Inject public MyBean(HelloService service) { this.service = service; } }
  • 11.
    DI IN SETTER public class MyBean { private HelloService service; @Inject public void setService(HelloService service) { this.service = service; } }
  • 12.
    DI IN FIELD public class MyBean { @Inject private HelloService service; public void displayHello() { display(service.hello(); } }
  • 13.
    NO TYPE ERASUREIN CDI public class MyBean { @Inject Service<User> userService; @Inject Service<Staff> staffService; } This works
  • 14.
    USING QUALIFIERS TODISTINGUISH BEANS OF THE SAME TYPE
  • 15.
    2 SERVICE IMPLEMENTATIONS… public interface HelloService { public String hello(); } public class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; } } public class EnglishHelloService implements HelloService { public String hello() { return "Hello World!"; } }
  • 16.
    …NEED QUALIFIERS… @Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD, PARAMETER}) public @interface French {} @Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD, PARAMETER}) public @interface English {}
  • 17.
    …TO BE DISTINGUISHED. @French public class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; } } @English public class EnglishHelloService implements HelloService { public String hello() { return "Hello World!"; } }
  • 18.
    QUALIFIED INJECTION POINTS public class MyBean { @Inject @French HelloService service; public void displayHello() { display( service.hello(); } } public class MyBean { @Inject @English HelloService service; public void displayHello() { display( service.hello(); } }
  • 19.
    QUALIFIERS CAN HAVEMEMBERS @Qualifier @Retention(RUNTIME) @Target({FIELD, TYPE, METHOD, PARAMETER}) public @interface Language { Languages value(); @Nonbinding String description() default ""; public enum Languages { FRENCH, ENGLISH } }
  • 20.
    QUALIFIERS WITH MEMBERS1/2 @Language(FRENCH) public class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; } } @Language(ENGLISH) public class EnglishHelloService implements HelloService { public String hello() { return "Hello World!"; } }
  • 21.
    QUALIFIERS WITH MEMBERS2/2 public class MyBean { @Inject @Language(ENGLISH) HelloService service; public void displayHello() { display( service.hello(); } } public class MyBean { @Inject @Language(FRENCH) HelloService service; public void displayHello() { display( service.hello(); } }
  • 22.
    MULTIPLE QUALIFIERS publicclass MyBean { @Inject @French HelloService service; } @French @Console @Secured public class FrenchHelloService implements HelloService { }
  • 23.
    MULTIPLE QUALIFIERS publicclass MyBean { @Inject @French @Console HelloService service; } @French @Console @Secured public class FrenchHelloService implements HelloService { }
  • 24.
    MULTIPLE QUALIFIERS publicclass MyBean { @Inject @French @Console @Secured HelloService service; } @French @Console @Secured public class FrenchHelloService implements HelloService { }
  • 25.
    MULTIPLE QUALIFIERS publicclass MyBean { @Inject @French @Console @Secured HelloService service; } @French @Secured public class FrenchHelloService implements HelloService { }
  • 26.
  • 27.
  • 28.
    SOMETIMES CALLED “LAZYINJECTION” public class MyBean { @Inject Instance<HelloService> service; public void displayHello() { display( service.get().hello() ); } }
  • 29.
    CHECK BEAN EXISTENCEAT RUNTIME public class MyBean { @Inject Instance<HelloService> service; public void displayHello() { if (!service.isUnsatisfied()) { display( service.get().hello() ); } } }
  • 30.
    INSTANCE<T> IS ITERABLE public interface Instance<T> extends Iterable<T>, Provider<T> { public Instance<T> select(Annotation... qualifiers); public <U extends T> Instance<U> select(Class<U> subtype, Annotation... qualifiers); public <U extends T> Instance<U> select(TypeLiteral<U> subtype, Annotation... qualifiers); public boolean isUnsatisfied(); public boolean isAmbiguous(); public void destroy(T instance); }
  • 31.
    LOOP ON ALLBEANS OF A GIVEN TYPE public class MyBean { @Inject @Any Instance<HelloService> services; public void displayHello() { for (HelloService service : services) { display( service.hello() ); } } }
  • 32.
    SELECT A QUALIFIERAT RUNTIME public class MyBean { @Inject @Any Instance<HelloService> services; public void displayHello() { display( service.select( new AnnotationLiteral()<French> {}) .get() ); } }
  • 33.
  • 34.
    CONTEXTS MANAGE BEANSLIFECYCLE • They helps container to choose when a bean should be instantiated and destroyed • They enforce the fact that a given bean is a singleton for a given context • Built-in CDI contexts : • @Dependent (default) • @ApplicationScoped, @SessionScoped, @RequestScoped • @ConversationScoped • @Singleton • You can create your own scope
  • 35.
    CHOOSING THE RIGHTCONTEXT @SessionScoped public class CartBean { public void addItem(Item item) { ... } }
  • 36.
    CHOOSING THE RIGHTCONTEXT @ApplicationScoped public class CartBean { public void addItem(Item item) { ... } } FAIL !!!
  • 37.
    CONVERSATION IS MANAGEBY DEV @ConversationScoped public class CartBean { public void addItem(Item item) { ... } }
  • 38.
    NEW CONTEXTS CANBE CREATED @ThreadScoped public class CartBean { public void addItem(Item item) { ... } }
  • 39.
  • 40.
    CREATING BEAN FROMANY CLASS @Produces public MyNonCDIClass myProducer() { return new MyNonCdiClass(); } ... @Inject MyNonCDIClass bean;
  • 41.
    PRODUCERS MAY HAVEA SCOPE @Produces @RequestScoped public FacesContext produceFacesContext() { return FacesContext.getCurrentInstance(); }
  • 42.
    GETTING INFO FROMINJECTION POINT @Produces public Logger produceLog(InjectionPoint injectionPoint) { return Logger.getLogger(injectionPoint.getMember() .getDeclaringClass().getName()); }
  • 43.
    REMEMBER : “NOTYPE ERASURE” @Produces public <K, V> Map<K, V> produceMap(InjectionPoint ip) { if (valueIsNumber(ip.getType())) { return new TreeMap<K, V>(); } return new HashMap<K, V>(); }
  • 44.
  • 45.
    A NICE WAYTO ADD DECOUPLING public class FirstBean { @Inject Event<Post> postEvent; public void saveNewPost(Post myPost) { postEvent.fire(myPost); } } public class SecondBean { public void listenPost(@Observes Post post) { System.out.println("Received : " + evt.message()); } }
  • 46.
    EVENTS CAN BEQUALIFIED public class FirstBean { @Inject Event<Post> postEvent; public void saveNewPost(Post myPost) { postEvent.select( new AnnotationLiteral()<French> {}).fire(myPost); } } public class SecondBean { // these 3 observers will be called public void listenFrPost(@Observes @French Post post) {} public void listenPost(@Observes Post post) {} public void listenObject(@Observes Object obj) {} // This one won’t be called public void listenEnPost(@Observes @English Post post) {} }
  • 47.
    AS ALWAYS “NOTYPE ERASURE” public class SecondBean { // these observers will be resolved depending // on parameter in event payload type public void listenStrPost(@Observes Post<String> post) {} public void listenNumPost(@Observes Post<Number> post) {} }
  • 48.
    SOME BUILT-IN EVENTS public class SecondBean { public void beginRequest(@Observes @Initialized(RequestScoped.class) ServletRequest req) {} public void endRequest(@Observes @Destroyed(RequestScoped.class) ServletRequest req) {} public void beginSession(@Observes @Initialized(SessionScoped.class) HttpSession session) {} public void endSession(@Observes @Destroyed(SessionScoped.class) HttpSession session) {} }
  • 49.
  • 50.
    A DECORATOR @Decorator @Priority(Interceptor.Priority.APPLICATION) public class HelloDecorator implements HelloService { // The decorated service may be restricted with qualifiers @Inject @Delegate HelloService service; public String hello() { return service.hello() + "-decorated"; } }
  • 51.
    INTERCEPTOR BINDING… @InterceptorBinding @Target({METHOD, TYPE}) @Retention(RUNTIME) public @interface Loggable {}
  • 52.
    …IS USED TOBIND AN INTERCEPTOR @Interceptor @Loggable @Priority(Interceptor.Priority.APPLICATION) public class LogInterceptor { @AroundInvoke public Object log(InvocationContext ic) throws Exception { System.out.println("Entering " + ic.getMethod().getName()); try { return ic.proceed(); } finally { System.out.println("Exiting " + ic.getMethod().getName()); } } }
  • 53.
    IT CAN BEPUT ON CLASS OR METHOD @Loggable public class MyBean { @Inject HelloService service; public void displayHello() { display( service.hello(); } }
  • 54.
    THAT’S ALL FORBASIC CDI • If you want to learn advanced stuff come to : Going Farther with CDI 1.2 [CON5585] Monday 5:30pm • visit : http://cdi-spec.org • follow @cdispec and @antoine_sd on twitter • Questions ?