Introduction to CDI

Preview:

Citation preview

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

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 Bean including (EJB session beans)

• 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 INITIALISER METHODpublic class MyBean {

    private HelloService service;

    @Inject    public void initService(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

TYPES OF A BEAN

• A bean will be a candidate for all “injection point” whose type belongs to its types set

• Bean types set contains its type, all its implementing interfaces and all its ancestors including Object.

• Bean types can be restricted by using @Typed annotation (Object is always in the set)

TYPES OF A BEANpublic class HelloService { //Types set : HelloService, Object} public class FrenchHelloService extends GenericService implements HelloService { //Types set : FrenchHelloService, GenericService, HelloService, Object } @Typed({HelloService.class,GenericService.class}) public class FrenchHelloService extends GenericService implements HelloService { //Types set : GenericService, HelloService, Object }

USING QUALIFIERS TO DISTINGUISH BEANS OF THE SAME TYPE

TWO 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() );        }    }}

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;

DISPOSER ARE OPTIONAL

@Producespublic MyNonCDIClass myProducer() {return new MyNonCdiClass();}

// Will be call at the instance end of lifepublic void releaseMyInstance(@Disposes MyNonCdiClass inst) {inst.clean();}

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());}

REMEMBER : “NO TYPE ERASURE”

@Producespublic <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 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) {}}

DECORATORS & INTERCEPTORS

INTERCEPTOR VS DECORATOR• They are two Aspect Oriented mechanism

• Interceptor is technical oriented : transaction, security, logging

• Interceptor can be bound to any bean or bean method

• Decorator is business oriented : change the behaviour of a bean

• Decorator is for a given bean class

DECORATOR

• To use a decorator, your bean should implement an interface

• The decorator will implement the same interface and will be annotated with @Decorator annotation

• It can be an abstract class (to avoid choosing methods to decorate)

• A decorator injects the bean it decorates with @Delegate annotation

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

Interceptor Binding Annotation

Interceptor Class

+

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();    }}

OTHER FEATURES

• Stereotypes: to create annotation gathering multiple annotations

• Alternatives: to provide alternative to a bean for tests or specific environments

• Specialization : to completely override an existing bean

• Check the spec on http://cdi-spec.org

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 ?

Recommended