1/3 : introduction to CDI - Antoine Sabot-Durand
-
Upload
soat -
Category
Technology
-
view
283 -
download
0
description
Transcript of 1/3 : introduction to CDI - Antoine Sabot-Durand
![Page 1: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/1.jpg)
INTRODUCTION TO CONTEXTS AND DEPENDENCY INJECTION (CDI)
@antoine_sd
![Page 2: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/2.jpg)
ANTOINE SABOT-DURAND
• Senior Software Engineer @Red Hat
• Java & OSS :
• CDI co-spec lead
• CDI community development
• Tech Lead on Agorava
• @antoine_sd
![Page 3: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/3.jpg)
WHAT IS CDI ?
• Java EE dependency injection standard• Strong typed and type safe• Context management• Observer pattern included (Event bus)• Highly extensible
![Page 4: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/4.jpg)
Previously on CDI
![Page 5: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/5.jpg)
A BIT OF HISTORY
Dec 2009 June 2013 Apr 2014 Sep 2014
CDI 1.0 (Java EE
6)
CDI 1.1 (Java EE
7)
CDI 1.2 (1.1 M
R)
CDI 2.0 Starts
Q1 2016
CDI 2.0 released
![Page 6: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/6.jpg)
IMPLEMENTATIONSJBoss Weld (Reference Implementation) Apache Open WebBeans
![Page 7: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/7.jpg)
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
![Page 8: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/8.jpg)
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.
![Page 9: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/9.jpg)
BASIC DEPENDENCY INJECTION
@Inject
![Page 10: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/10.jpg)
THIS IS A BEAN
public class HelloService { public String hello() { return "Hello World!"; }}
![Page 11: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/11.jpg)
DI IN CONSTRUCTORpublic class MyBean {
private HelloService service;
@Inject public MyBean(HelloService service) { this.service = service; }}
![Page 12: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/12.jpg)
DI IN SETTERpublic class MyBean {
private HelloService service;
@Inject public void setService(HelloService service) { this.service = service; }}
![Page 13: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/13.jpg)
DI IN FIELDpublic class MyBean { @Inject private HelloService service;
public void displayHello() { display(service.hello(); }}
![Page 14: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/14.jpg)
NO TYPE ERASURE IN CDI
public class MyBean {
@Inject Service<User> userService;
@Inject Service<Staff> staffService; }
![Page 15: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/15.jpg)
NO TYPE ERASURE IN CDI
public class MyBean {
@Inject Service<User> userService;
@Inject Service<Staff> staffService; }
This w
orks
![Page 16: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/16.jpg)
USING QUALIFIERS TO DISTINGUISH BEANS OF THE SAME TYPE
![Page 17: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/17.jpg)
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!"; }}
![Page 18: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/18.jpg)
…NEED QUALIFIERS…@Qualifier@Retention(RUNTIME)@Target({FIELD, TYPE, METHOD, PARAMETER}) public @interface French {}
@Qualifier@Retention(RUNTIME)@Target({FIELD, TYPE, METHOD, PARAMETER}) public @interface English {}
![Page 19: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/19.jpg)
…TO BE DISTINGUISHED.
@Frenchpublic class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; }}
@Englishpublic class EnglishHelloService implements HelloService { public String hello() { return "Hello World!"; }}
![Page 20: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/20.jpg)
QUALIFIED INJECTION POINTSpublic 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(); }}
![Page 21: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/21.jpg)
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 }}
![Page 22: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/22.jpg)
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!"; }}
![Page 23: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/23.jpg)
QUALIFIERS WITH MEMBERS 2/2public 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(); }}
![Page 24: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/24.jpg)
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French HelloService service;}
@French @Console @Securedpublic class FrenchHelloService implements HelloService {
}
![Page 25: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/25.jpg)
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French @Console HelloService service;}
@French @Console @Securedpublic class FrenchHelloService implements HelloService {
}
![Page 26: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/26.jpg)
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French @Console @Secured HelloService service;}
@French @Console @Securedpublic class FrenchHelloService implements HelloService {
}
![Page 27: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/27.jpg)
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French @Console @Secured HelloService service;}
@French @Securedpublic class FrenchHelloService implements HelloService {
}
![Page 28: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/28.jpg)
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French @Console @Secured HelloService service;}
@French @Securedpublic class FrenchHelloService implements HelloService {
}
![Page 29: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/29.jpg)
RESERVED QUALIFIERS
@Default@Any@Named
![Page 30: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/30.jpg)
PROGRAMMATIC LOOKUP
![Page 31: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/31.jpg)
SOMETIMES CALLED “LAZY INJECTION”
public class MyBean {
@Inject Instance<HelloService> service;
public void displayHello() { display( service.get().hello() ); }}
![Page 32: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/32.jpg)
CHECK BEAN EXISTENCE AT RUNTIMEpublic class MyBean {
@Inject Instance<HelloService> service;
public void displayHello() { if (!service.isUnsatisfied()) { display( service.get().hello() ); } }}
![Page 33: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/33.jpg)
INSTANCE<T> IS ITERABLEpublic 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);}
![Page 34: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/34.jpg)
LOOP ON ALL BEANS OF A GIVEN TYPEpublic class MyBean {
@Inject @Any Instance<HelloService> services;
public void displayHello() { for (HelloService service : services) { display( service.hello() ); } }}
![Page 35: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/35.jpg)
SELECT A QUALIFIER AT RUNTIMEpublic class MyBean {
@Inject @Any Instance<HelloService> services;
public void displayHello() { display( service.select( new AnnotationLiteral()<French> {}) .get() ); }}
![Page 36: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/36.jpg)
CONTEXTS
![Page 37: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/37.jpg)
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
![Page 38: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/38.jpg)
CHOOSING THE RIGHT CONTEXT
@SessionScopedpublic class CartBean {
public void addItem(Item item) { ... } }
![Page 39: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/39.jpg)
CHOOSING THE RIGHT CONTEXT
@ApplicationScopedpublic class CartBean {
public void addItem(Item item) { ... } }
![Page 40: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/40.jpg)
CHOOSING THE RIGHT CONTEXT
@ApplicationScopedpublic class CartBean {
public void addItem(Item item) { ... } } FAI
L !!!
![Page 41: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/41.jpg)
CONVERSATION IS MANAGE BY DEV
@ConversationScopedpublic class CartBean {
public void addItem(Item item) { ... } }
![Page 42: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/42.jpg)
NEW CONTEXTS CAN BE CREATED
@ThreadScopedpublic class CartBean {
public void addItem(Item item) { ... } }
![Page 43: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/43.jpg)
PRODUCERS
![Page 44: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/44.jpg)
CREATING BEAN FROM ANY CLASS
@Producespublic MyNonCDIClass myProducer() {return new MyNonCdiClass();}...@InjectMyNonCDIClass bean;
![Page 45: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/45.jpg)
PRODUCERS MAY HAVE A SCOPE
@Produces@RequestScopedpublic FacesContext produceFacesContext() { return FacesContext.getCurrentInstance();}
![Page 46: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/46.jpg)
GETTING INFO FROM INJECTION POINT
@Producespublic Logger produceLog(InjectionPoint injectionPoint) { return Logger.getLogger(injectionPoint.getMember() .getDeclaringClass().getName());}
![Page 47: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/47.jpg)
EVENTS
![Page 48: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/48.jpg)
A NICE WAY TO ADD DECOUPLINGpublic 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()); }}
![Page 49: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/49.jpg)
EVENTS CAN BE QUALIFIEDpublic 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) {}}
![Page 50: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/50.jpg)
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) {}}
![Page 51: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/51.jpg)
SOME BUILT-IN EVENTSpublic 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) {}}
![Page 52: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/52.jpg)
STEREOTYPES TO AVOID ANNOTATIONS HELL
![Page 53: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/53.jpg)
BUILT-IN STEREOTYPE
@Named@RequestScoped@Documented@Stereotype@Target({ TYPE, METHOD, FIELD }) @Retention(RUNTIME) public @interface Model { }
![Page 54: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/54.jpg)
MY STEREOTYPE@Named@SessionScoped @MyQualifier @MyOtherQualifier@Documented@Stereotype@Target({ TYPE, METHOD, FIELD }) @Retention(RUNTIME) public @interface MyModel { }
![Page 55: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/55.jpg)
USAGE
@MyModelpublic class CircularBean {
}
![Page 56: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/56.jpg)
DECORATORS & INTERCEPTORS
![Page 57: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/57.jpg)
A DECORATOR
@Decorator@Priority(Interceptor.Priority.APPLICATION)public abstract class HelloDecorator implements HelloService {
// The decorated service may be restricted with qualifiers @Inject @Delegate HelloService service;
public String hello() { return service.hello() + "-decorated"; }}
![Page 58: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/58.jpg)
INTERCEPTOR BINDING…
@InterceptorBinding@Target({METHOD, TYPE}) @Retention(RUNTIME)public @interface Loggable {}
![Page 59: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/59.jpg)
…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()); } } }
![Page 60: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/60.jpg)
IT CAN BE PUT ON CLASS OR METHOD
@Loggablepublic class MyBean {
@Inject HelloService service;
public void displayHello() { display( service.hello(); }}
![Page 61: 1/3 : introduction to CDI - Antoine Sabot-Durand](https://reader030.fdocuments.us/reader030/viewer/2022013011/558bce4fd8b42a960b8b4673/html5/thumbnails/61.jpg)
THAT’S ALL FOR BASIC CDI
• If you want to learn advanced stuff come to check my over talk : CDI advanced.
• follow @cdispec and @antoine_sd on twitter
• Questions ?