2. 1
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
Agenda
3. 2
Introduction to CDI
• Java EE dependency injection standard
• Can also be used in Java SE environments with
some help
• Strongly typed and type safe
• Provides context management
• Activated by default since CDI 1.1
• Use beans.xml to activate alternative beans, etc.
• Highly Extensible via CDI SPI (not covered here)
What is CDI?
4. 3
Introduction to CDI
• Managed Beans are basic components
• Managed by the container
• Have a lifecycle
• Can be intercepted (technical concerns)
and decorated (business concerns)
• Can be injected
• Are accessible outside CDI code
CDI Beans
5. 4
Agenda
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
7. 6
Basic Dependency Injection
public class MyBean {
private HowdyService service;
@Inject
public MyBean(HowdyService service) {
this.service = service;
}
}
Dependency Injection in Constructors
8. 7
Basic Dependency Injection
public class MyBean {
private HowdyService service;
@Inject
public void setService(HowdyService service) {
this.service = service;
}
}
Dependency Injection in Setter
9. 8
Basic Dependency Injection
public class MyBean {
@Inject
private HowdyService service;
public void sayHowdy() {
display(service.howdy());
}
}
Dependency Injection in Fields
10. 9
Basic Dependency Injection
This Works!
public class MyBean {
@Inject Service<User> userService;
@Inject Service<Staff> staffService;
}
No Type Erasure in CDI
11. 10
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
12. 11
Using Qualifiers to Distinguish Beans of the Same Type
public interface HelloService {
public String hello();
}
public class TexanHelloService implements HelloService {
public String hello() {
return "Howdy!";
}
}
public class AustralianHelloService implements HelloService {
public String hello() {
return "G’day!";
}
}
Multiple Service Implementations
13. 12
Using Qualifiers to Distinguish Beans of the Same Type
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD, PARAMETER})
public @interface Texan {}
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD, PARAMETER})
public @interface Australian {}
We Create Qualifiers
14. 13
Using Qualifiers to Distinguish Beans of the Same Type
@Texan
public class TexanHelloService implements HelloService {
public String hello() {
return "Howdy!";
}
}
@Australian
public class AussieHelloService implements HelloService {
public String hello() {
return "G’day!";
}
}
And Add Them to Our Implementations
15. 14
Using Qualifiers to Distinguish Beans of the Same Type
public class MyTexanBean {
@Inject @Texan HelloService service;
public void displayHello() {
display(service.hello());
}
}
public class MyAussieBean {
@Inject @Australian HelloService service;
public void displayHello() {
display(service.hello());
}
}
And Specify at our Injection Site
16. 15
Using Qualifiers to Distinguish Beans of the Same Type
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD, PARAMETER})
public @interface Language {
public enum Languages {
TEXAN, AUSTRALIAN
}
Languages value();
@Nonbinding String description() default "";
}
Qualifiers can have Members
17. 16
Using Qualifiers to Distinguish Beans of the Same Type
@Language(TEXAN)
public class TexanHelloService implements HelloService {
public String hello() {
return "Howdy!";
}
}
@Language(AUSTRALIAN)
public class AussieHelloService implements HelloService {
public String hello() {
return "G’day!";
}
}
Class definition for Qualifiers with Members
18. 17
Using Qualifiers to Distinguish Beans of the Same Type
public class MyTexanBean {
@Inject @Language(TEXAN) HelloService service;
public void displayHello() {
display(service.hello());
}
}
public class MyAussieBean {
@Inject @Language(AUSTRALIAN) HelloService service;
public void displayHello() {
display(service.hello());
}
}
Injection using Qualifiers with Members
19. 18
Using Qualifiers to Distinguish Beans of the Same Type
public class MyTexanBean {
@Inject @Texan HelloService service;
public void displayHello() {
display(service.hello());
}
}
@Texan @Console @Secured
public class TexanHelloService implements HelloService {
public String hello() {
return "Howdy!";
}
}
Multiple Qualifiers
20. 19
Using Qualifiers to Distinguish Beans of the Same Type
public class MyTexanBean {
@Inject @Texan @Console HelloService service;
public void displayHello() {
display(service.hello());
}
}
@Texan @Console @Secured
public class TexanHelloService implements HelloService {
public String hello() {
return "Howdy!";
}
}
Multiple Qualifiers
21. 20
Using Qualifiers to Distinguish Beans of the Same Type
public class MyTexanBean {
@Inject @Texan @Console @Secured HelloService service;
public void displayHello() {
display(service.hello());
}
}
@Texan @Console @Secured
public class TexanHelloService implements HelloService {
public String hello() {
return "Howdy!";
}
}
Multiple Qualifiers
22. 21
Using Qualifiers to Distinguish Beans of the Same Type
public class MyTexanBean {
@Inject @Texan @Console @Secured HelloService service;
public void displayHello() {
display(service.hello());
}
}
@Texan @Console
public class TexanHelloService implements HelloService {
public String hello() {
return "Howdy!";
}
}
Multiple Qualifiers – Won’t work
23. 22
Using Qualifiers to Distinguish Beans of the Same Type
@Default
@Any
@Named
Reserved Qualifiers
24. 23
Using Qualifiers to Distinguish Beans of the Same Type
public class MyBean {
@Inject @Any
Instance<HelloService> service;
public void displayHello() {
HelloService helloService =
service.select(new AnnotationLiteral<Texan>(){}).get();
display(helloService.hello());
}
}
Programmatic Bean Lookup (a.k.a. Lazy Injection)
25. 24
Using Qualifiers to Distinguish Beans of the Same Type
@Texan @Vetoed
public class TexanHelloService implements HelloService {
public String hello() {
return "Howdy!";
}
}
package-info.java class:
@Vetoed
package cdi_experiments;
import javax.enterprise.inject.Vetoed;
Ignoring Beans and Packages with @Vetoed
26. 25
Using Qualifiers to Distinguish Beans of the Same Type
@Texan @Alternative
public class MyHowdyYallService implements HelloService {
public String hello() {
return "Howdy y'all!";
}
}
<beans …>
<alternatives>
<class>cdi_experiments.MyHowdyYallService</class>
</alternatives>
</beans>
Specifying and using Alternative Beans
27. 26
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
28. 27
Contexts
Help the container to choose when a bean should be intstantiated and destroyed
Enforce singleton pattern for a given context
Built-in CDI contexts:
• @Dependent (default)
• @ApplicationScoped, @SessionScoped, @RequestSCoped
• @ConversationScoped
• @Singleton
You can create your own scope
Contexts Manage Bean Lifecycle
29. 28
Contexts
@SessionScoped
public class CartBean {
public void addItem(Item item) {
...
}
}
A shopping cart is almost always tied to a user’s session,
so using the @SessionScoped context makes the most
sense.
Choosing the Right Context
31. 30
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
32. 31
Producers and Disposers
@Produces
public OldRanchHand oldRanchHandProducer() {
return new OldRanchHand();
}
…
@Inject OldRanchHand ranchHand;
The return type and the injection type are identical. CDI uses this type information to inject produced
values.
To inject different values into different injection points of the same type, use qualifiers
Method producers can be used to generate complex objects
Create a Bean from any Class
33. 32
Producers and Disposers
@Produces
public Logger produceLog(InjectionPoint injectionPoint) {
return Logger.getLogger(injectionPoint.getMember()
.getDeclaringClass().getName());
}
Getting Injection Point Information
34. 33
Producers and Disposers
@Produces
public <K, V> Map<K, V> produceMap(InjectionPoint ip) {
if (valueIsNumber(ip.getType())) {
return new TreeMap<K, V>();
}
return new HashMap<K, V>();
}
No Type Erasure Enables Fancy Stuff
35. 34
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
36. 35
Events
public class MyTexanBean {
@Inject Event<HelloService> helloEvent;
@Inject @Texan HelloService service;
public void displayHello() {
display(service.hello());
}
public void iSaidHowdy(HelloService helloService) {
helloEvent.fire(helloService);
}
}
public class HelloListenerBean {
public void listenForHello(@Observes HelloService hello) {
System.out.println(hello.hello() + " to you too!");
}
}
37. 36
Events
public class HelloListenerBean {
public void listenForHello(@Observes @Texan HelloService hello) {
System.out.println(hello.hello() + " to you too!");
}
}
Qualifiers on Observers
38. 37
Events
The producer must wait for all observers to execute before
continuing
If any observer throws an exception, all remaining observer
methods are not called and the exception is thrown by the
firing observing method
Observers have no priority in CDI 1.1, but is on the
roadmap for 2.0
Some Caveats
39. 38
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
40. 39
Interceptors
Classes that provide technical cross-cutting functionality
are interceptors
Technical cross-cutting concerns include:
• Transactions
• Security
• Logging
Interceptors are not enabled by default, but can be enabled
and ordered in beans.xml
Interceptors can have multiple qualifiers
Interceptors
41. 40
Interceptors
Interceptor bindings are qualifiers that instruct the CDI
container to intercept a method or all methods on a class
@InterceptorBinding
@Target({METHOD, TYPE})
@Retention(RUNTIME)
public @interface Loggable {}
Qualified Interceptor Binding
44. 43
Interceptors
@Interceptor @Loggable
public class FriendlyCowboy {
@PostConstruct
public void smile(InvocationContext invocationContext) {
//smile
}
@PreDestroy
public void tipHat(InvocationContext invocationContext) {
//tip hat
}
}
Lifecycle Interceptors
45. 44
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
46. 45
Decorators
Classes that provide additional business functionality are decorators
Interceptors are called before decorators
Decorator classes must implement the same interface(s) as the
classes that they are decorating
Can be abstract if it only decorates some of the methods in the
interface
Enabled in the <decorators> section in the beans.xml file and can be
enabled and ordered in the beans.xml and via the @Priority
annotation
Decorators
47. 46
Decorators
@Decorator
public abstract class HelloDec implements HelloService {
// The decorated service may be restricted with qualifiers
@Inject
@Delegate
HelloService service;
public String hello() {
return service.hello() + "-decorated";
}
}
Short Example
48. 47
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
49. 48
CDI in Java SE
Currently possible through the DeltaSpike library
Slated for standardization in CDI 2.0
public class MainApp {
public static void main(String[] args) {
CdiContainer cdiContainer = CdiContainerLoader.getCdiContainer();
cdiContainer.boot();
// Starting the application-context enables use of @ApplicationScoped beans
ContextControl contextControl = cdiContainer.getContextControl();
contextControl.startContext(ApplicationScoped.class);
// You can use CDI here
//...
cdiContainer.shutdown();
}
}
CDI – Not Just for JEE!
50. 49
1 Introduction to CDI
2 Basic Dependency Injection
3 Using Qualifiers to Distinguish Beans of the Same Type
4 Contexts
5 Producers and Disposers
6 Events
7 Interceptors
8 Decorators
9 CDI in Java SE
10 Using CDI and JPA Together
51. 50
Using CDI and JPA Together
CDI Beans and JPA Beans have different lifecycles
As a result, CDI Beans can’t be injected directly into JPA Beans
EntityListeners can be used to bridge CDI and JPA when needed
CDI and JPA – Friends at Last
52. 51
Using CDI and JPA Together
@Entity
@EntityListeners(PostListener.class)
public class Post implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "CREATED_DATE")
private Date created;
@Column(name = "LAST_MODIFIED_DATE")
private Date lastModified;
public Date getCreated() { return created; }
public void setCreated(Date created) { this.created = created; }
public Date getLastModified() { return lastModified; }
public void setLastModified(Date lastModified) { this.lastModified = lastModified;}
}
The JPA Class
53. 52
Using CDI and JPA Together
public class PostListener {
@Inject Logger log;
@PrePersist
public void prePresist(Object o) {
log.info("call prePresist");
if (o instanceof Post) {
Post post = (Post) o;
final Date created = new Date();
post.setCreated(created);
post.setLastModified(created);
}
}
@PreUpdate
public void preUpdate(Object o) {
log.info("call preUpdate");
if (o instanceof Post) {
Post post = (Post) o;
post.setLastModified(new Date());
}
}
}
Editor's Notes
Two injection points with different parameterized types. CDI can differentiate between these two types, without the need to introduce extra code.But what if we have two implementations of the same interface?
Here we have two implementations of the HelloService
CDI can now determine which implementation you want to use
Ideally, you’ll want to have Boolean and Enum members to keep things as type-safe and controlled as possible. The @Nonbinding annotation indicates that the description value will not be considered for injection target matching
The container will find the HelloService qualified with the Texan qualifier
The container will find the HelloService qualified with both with the Texan and Console qualifiers
The container will find the HelloService qualified with both with the Texan, Console, and Secured qualifiers
However, the container will not find the HelloService qualified with the Texan, Console, and Secured qualifiers since there is no bean with all qualifier types – we only have Texan and Console qualifiers on the TexanHelloService
@Default is the qualifier that is applied to all beans that don’t have qualifiers
@Any – used in programmatic lookup
@Named – exception in strong typing – used to give a name to a bean to access bean via JSF view or JSP page
The Any qualifer says to inject an instance of HelloService regardless of their qualifier. Here we’re selecting the Texan service through the use of the AnnotationLiteral abstract class, which supports inline instantiation of annotation type instances.
In this case, the TexanHelloService class will be ignored by the CDI container since it is marked as @Vetoed
To veto an entire package, mark the package as @Vetoed in the package-info.java class
Instead of saying Howdy! all injected Texan beans will say Howdy y’all since it is activated in the alternatives section of the beans.xml
Useful both in testing to inject test beans to isolate behavior
Useful in production environments to enable different behavior depending on requirements
Turns a POJO into a CDI bean and alllows 3rd party frameworks to be used by CDI by exposing their objects as CDI beans
Producers allow additional control over object creation
You can also have @Alternative producers
The InjectionPoint class allows for programmatic retrieval of some information about the injection site class.
Since CDI doesn’t erase type information, we can use generic type information in our code
Events allow for the decoupling of producers and consumers
Require no compile-time dependencies
Events can be qualified to only listen for events from specific beans
Interceptors can have multiple qualifiers or can use qualifiers with members to allow the CDI container to differentiate interceptors
Interceptors can be @Vetoed
Interceptor classes must be annotated / qualified with the @Interceptor annotation and at least one other qualifier
The intercepting method must be annotated with @AroundInvoke
Interceptor methods must take an InvocationContext type as a parameter and return Object and call the proceed method once it’s done.
Wrap the proceed() method call in a try/finally block to execute code if the intercepted method needs to have additional code executed after it completes / exits
Interceptors are executed in the order they are defined in beans.xml, but only in that archive
Interceptors can be ordered for an entire application using the @Priority annotation -- smaller priority called first. Defined in the qualifier / annotation class
Interceptor annotations can be declared on individual methods, or they can be placed on all public methods by annotating the class with the interceptor
Annotate the method on the CDI bean you want executed at the appropriate point in the life cycle
Lifecycle @Interceptor beans can be defined and can be applied to multiple CDI managed beans.
The methods annotated with @PostConstruct and @PreDestroy must take an InvocationContext as a parameter and return void
Starting the container does not automatically start all CDI Contexts.
Contexts must be started independently using DeltaSpike’s provided ContextControl class.
Bare bones blog post JPA example
From http://hantsy.blogspot.com/2013/12/jpa-21-cdi-support.html
Logger is injected and invoked on JPA lifecycle event occurrences