1/3 : introduction to CDI - Antoine Sabot-Durand
-
Upload
soat -
Category
Technology
-
view
282 -
download
0
description
Transcript of 1/3 : introduction to CDI - Antoine Sabot-Durand
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
Previously on CDI
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
IMPLEMENTATIONSJBoss 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 CONSTRUCTORpublic class MyBean {
private HelloService service;
@Inject public MyBean(HelloService service) { this.service = service; }}
DI IN SETTERpublic class MyBean {
private HelloService service;
@Inject public void setService(HelloService service) { this.service = service; }}
DI IN FIELDpublic 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; }
NO TYPE ERASURE IN CDI
public class MyBean {
@Inject Service<User> userService;
@Inject Service<Staff> staffService; }
This w
orks
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.
@Frenchpublic class FrenchHelloService implements HelloService { public String hello() { return "Bonjour tout le monde!"; }}
@Englishpublic class EnglishHelloService implements HelloService { public String hello() { return "Hello World!"; }}
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(); }}
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/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(); }}
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French HelloService service;}
@French @Console @Securedpublic class FrenchHelloService implements HelloService {
}
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French @Console HelloService service;}
@French @Console @Securedpublic class FrenchHelloService implements HelloService {
}
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French @Console @Secured HelloService service;}
@French @Console @Securedpublic class FrenchHelloService implements HelloService {
}
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French @Console @Secured HelloService service;}
@French @Securedpublic class FrenchHelloService implements HelloService {
}
MULTIPLE QUALIFIERS
public class MyBean { @Inject @French @Console @Secured HelloService service;}
@French @Securedpublic 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 RUNTIMEpublic class MyBean {
@Inject Instance<HelloService> service;
public void displayHello() { if (!service.isUnsatisfied()) { display( service.get().hello() ); } }}
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);}
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() ); } }}
SELECT A QUALIFIER AT RUNTIMEpublic 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
@SessionScopedpublic class CartBean {
public void addItem(Item item) { ... } }
CHOOSING THE RIGHT CONTEXT
@ApplicationScopedpublic class CartBean {
public void addItem(Item item) { ... } }
CHOOSING THE RIGHT CONTEXT
@ApplicationScopedpublic class CartBean {
public void addItem(Item item) { ... } } FAI
L !!!
CONVERSATION IS MANAGE BY DEV
@ConversationScopedpublic class CartBean {
public void addItem(Item item) { ... } }
NEW CONTEXTS CAN BE CREATED
@ThreadScopedpublic class CartBean {
public void addItem(Item item) { ... } }
PRODUCERS
CREATING BEAN FROM ANY CLASS
@Producespublic MyNonCDIClass myProducer() {return new MyNonCdiClass();}...@InjectMyNonCDIClass bean;
PRODUCERS MAY HAVE A SCOPE
@Produces@RequestScopedpublic FacesContext produceFacesContext() { return FacesContext.getCurrentInstance();}
GETTING INFO FROM INJECTION POINT
@Producespublic Logger produceLog(InjectionPoint injectionPoint) { return Logger.getLogger(injectionPoint.getMember() .getDeclaringClass().getName());}
EVENTS
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()); }}
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) {}}
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 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) {}}
STEREOTYPES TO AVOID ANNOTATIONS HELL
BUILT-IN STEREOTYPE
@Named@RequestScoped@Documented@Stereotype@Target({ TYPE, METHOD, FIELD }) @Retention(RUNTIME) public @interface Model { }
MY STEREOTYPE@Named@SessionScoped @MyQualifier @MyOtherQualifier@Documented@Stereotype@Target({ TYPE, METHOD, FIELD }) @Retention(RUNTIME) public @interface MyModel { }
USAGE
@MyModelpublic class CircularBean {
}
DECORATORS & INTERCEPTORS
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"; }}
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
@Loggablepublic 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 check my over talk : CDI advanced.
• follow @cdispec and @antoine_sd on twitter
• Questions ?