Download Contexts and Dependency Injection

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts
no text concepts found
Transcript
Contexts and Dependency Injection
Contents
1.
Overview of CDI
2.
Bean scopes
3.
Qualifiers
4.
Producers
5.
Additional techniques
2
1. Overview of CDI

What is CDI?

What kinds of object can be injected?

Understanding the need for CDI

Using CDI to inject dependencies

Allowable injection points

Bean names
3
What is CDI?

CDI= Contexts and Dependency Injection

Contexts
•

Dependency injection
•
•

Enables you to bind the lifecycle and interactions of stateful
components to lifecycle contexts
Allows you to inject components into an application in a type-safe
manner
You can choose at deployment time which implementation of a
particular interface to inject
Note: Interfaces play a vital role in CDI
•
Allows different implementations to be injected easily
4
What Kinds of Object can be Injected?

CDI allows you to inject the following kinds of objects:
•
•
•
•
•
•
•
Almost any Java class
Java EE session beans
Java EE resources
Persistence contexts
Producer fields, and objects returned by producer methods
Web service references
Remote enterprise bean references
5
Understanding the Need for CDI (1 of 2)

Imagine a repository that gets records from a data store

Here's an interface
•
Describes the repository capabilities
public interface Repository {
String getRecord(int id);
}

Repository.java
Here's a simple implementation
•
Just returns hard-coded data - that's fine!
public class SqlRepository1 implements Repository {
@Override
public String getRecord(int id) {
return "This is record " + id;
}
}
SqlRepository1.java
6
Understanding the Need for CDI (2 of 2)

Now imagine a servlet needs a repository object
•

We can say that the repository is a dependency of the servlet
The servlet could instantiate its dependencies itself…
public class MyServlet1 extends HttpServlet {
private Repository repository;
@Override
public void init() {
repository = new SqlRepository1();
}
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
String data = repository.getRecord(42);
resp.getWriter().write("Record obtained via MyServlet1: " + data);
}
}
MyServlet1.java
7
Using CDI to Inject Dependencies (1 of 2)


We can use CDI to inject a repository automatically into
the servlet
The first step is to annotate the dependency class with a
lifecycle annotation, e.g. @RequestScoped
•
Tells CDI when to create / destroy the dependency object
import javax.enterprise.context.RequestScoped;
@RequestScoped
public class SqlRepository2 implements Repository {
@Override
public String getRecord(int id) {
return "This is record " + id;
}
}
SqlRepository2.java
8
Using CDI to Inject Dependencies (2 of 2)

Our servlet can now have its dependencies injected
automatically by the CDI runtime
•
Annotate dependencies with @Inject
import javax.inject.Inject;
…
public class MyServlet2 extends HttpServlet {
@Inject
private Repository repository;
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
String data = repository.getRecord(42);
resp.getWriter().write("Record obtained via MyServlet2: " + data);
}
}
MyServlet2.java
9
Allowable Injection Points
Field
@Inject
private Repository repository;
Constructor
private Repository repository;
@Inject
public MyServlet2(Repository r) {
repository = r;
}
Setter
private Repository repository;
@Inject
public void setRepository(Repository r) {
repository = r;
}
Initialization
method
private Repository repository;
@Inject
public void init(Repository r) {
repository = r;
}
10
Bean Names

If you want to make a bean accessible in EL, you must
annotate the bean with @Named
@Named
@RequestScoped
public class Timestamp {
public String getCurrentDate() { … }
public String getCurrentTime() { … }
}

Timestamp.java
You can then use the bean in EL in JSP and Facelets pages
<html … >
…
<f:view>
Current date: <h:outputText value="#{timestamp.currentDate}" />
<br/>
Current time: <h:outputText value="#{timestamp.currentTime}" />
</f:view>
…
NamedBeansDemo.xhtml
</html>
11
2. Bean Scopes

Allowable bean scopes

Understanding conversation scope

Example of conversation scope
12
Allowable Bean Scopes
Scope
Annotation
Duration
Request
@RequestScoped
User's interaction with a web app in a single request.
View
@ViewScoped
User's interaction with the same page in a web app (JSF 2.2).
Session
@SessionScoped
User's interaction with a web app across multiple requests.
Application
@ApplicationScoped
Shared state across all users' interactions with a web app.
Dependent
@Dependent
The default scope if none is specified. It means an object
exists to serve exactly one client bean and has the same
lifecycle as that client bean.
Conversation
@ConversationScoped
User's interaction with a servlet, including JSF apps. The
conversation scope exists within developer-controlled
boundaries that extend it across multiple requests for longrunning conversations.
13
Understanding Conversation Scope

To define a CDI bean with conversation scope:
•
•
•

To start / stop conversational state:
•

Annotate the CDI bean class with @ConversationScoped
Note, the class must implement Serializable
Inject a conversation bean of type @Conversation
Call the conversation bean's begin() and end() methods
Example:
@Named
@ConversationScoped
public class ConversationManager implements java.io.Serializable {
@Inject
private Conversation conversation;
public void someStartMethod() { conversation.begin(); … }
public void someEndMethod()
{ conversation.end();
… }
…
}
ConversationManager.java
14
Example of Conversation Scope

Run the ConversationScopeDemo.xhtml demo file
15
3. Qualifiers

Defining a qualifier annotation

Applying a qualifier annotation

Using a qualifier in an injection
16
Defining a Qualifier Annotation


You can define a qualifier annotation as a means of
differentiating several bean implementations
Example:
import javax.inject.Qualifier;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import
import
import
import
import
static
static
static
static
static
java.lang.annotation.RetentionPolicy.RUNTIME;
java.lang.annotation.ElementType.TYPE;
java.lang.annotation.ElementType.METHOD;
java.lang.annotation.ElementType.FIELD;
java.lang.annotation.ElementType.PARAMETER;
@Qualifier
@Retention(RUNTIME)
@Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Logging {}
Logging.java
17
Applying a Qualifier Annotation


You can annotate bean implementations with your qualifier
annotation
Example:
@RequestScoped
@Logging
public class SqlRepository3 implements Repository {
@Override
public String getRecord(int id) {
System.out.printf("[%s] : getRecord(%d) invoked\n", new Date(), id);
return "This is record " + id;
}
}
SqlRepository3.java
18
Using a Qualifier in an Injection


You can use a qualifier annotation in an injection, to
specify you want a particular type of implementation
Example:
public class MyServlet3 extends HttpServlet {
@Inject
@Logging
private Repository repository;
…
}
MyServlet3.java
19
4. Producers

Defining producer fields and methods

Using produced values

Producing Java EE resources

Disposing produced objects
20
Defining Producer Fields and Methods

Producers are a way to allow non-beans to be injected
•
•

E.g. primitives, or objects not in a bean archive
E.g. objects requiring complex construction
Example:
@RequestScoped
public class Numbers {
@Produces
@MaxNumber
private int maxNumber = 100;
private Random random = new Random(System.currentTimeMillis());
@Produces
@RandomNumber
public int next() {
return 1 + random.nextInt(maxNumber);
}
}
Numbers.java
21
Injecting Produced Values

To inject a produced value:
•

If the value varies at runtime:
•

Use @Inject, plus the appropriate qualifier annotation
Wrap produced field in Instance, and call get() to get value
Example:
public class MyServlet4 extends HttpServlet {
@Inject
@MaxNumber
private int maxNumber;
@Inject
@RandomNumber
private Instance<Integer> randomNumber;
public void doGet(HttpServletRequest req, HttpServletResponse resp)
resp.getWriter().write("Max: " + max + ", " +
"Random number: " + rand.get());
}
}
{
MyServlet4.java
22
Producing Java EE Resources

You can use producers to allow Java EE resources to be
injected
•
•
•

JMS queues, topics, connection factories
Persistence contexts
Etc.
Example:
public class SomeBean {
@Produces
@SomeTopic
@Resource(name="topics/SomeTopic")
private Topic someTopic;
@Produces
@SomeDatabase
@PersistenceContext
private EntityManager entityManager;
…
}
23
Disposing Produced Objects

You can use producers to generate objects that need to be
disposed when the context is closed
•

Define a method with a parameter annotated with @Disposes
Example:
public class SomeBean {
@Produces
@SomeDatabase
@PersistenceContext
private EntityManager entityManager;
public void closeEntityManager(@Disposes @SomeDatabase EntityManager em) {
em.close();
}
}
24
5. Additional Techniques

Predefined Java EE bean types

Stereotypes

Interceptors

Decorators

Using CDI in JSF
25
Predefined Java EE Bean Types

Java EE provides predefined beans that implement the
following interfaces
Predefined bean
Description
Injection example
UserTransaction
Resource
@Resource UserTransaction transaction;
Principal
Resource
@Resource Principal principal;
Validator
Resource
@Resource Validator validator;
ValidatorFactory
Resource
@Resource ValidatorFactory factory;
HttpServletRequest
CDI bean
@Inject HttpServletRequest request;
HttpSession
CDI bean
@Inject HttpSession session;
ServletContext
CDI bean
@Inject ServletContext context;
26
Stereotypes

Stereotypes are used to reduce the amount of boilerplate
code
@Stereotype
@Named
@RequestScoped
@Target(TYPE)
@Retention(RUNTIME)
public @interface RequestScopedSecureBean {}
@RequestScopedSecureBean
public class SomeBean {
…
}
27
Interceptors (1 of 4)

An interceptor is a special bean that intercepts calls on
other methods
•
•

Typically implements cross-cutting code such as security,
transactions, logging, etc.
Allows you to put all this low-level code in a single place, and have
the CDI runtime automatically call it
The first step is to define an interceptor binding
•
A special annotation, annotated with @InterceptorBinding
@InterceptorBinding
@Inherited
@Retention(RUNTIME)
@Target({METHOD, TYPE})
public @interface Audited {
}
Audited.java
28
Interceptors (2 of 4)

The next step is to implement the interceptor bean
@Dependent
@Audited
@Interceptor
public class AuditedInterceptor {
@AroundInvoke
public Object logMethodEntry(InvocationContext ic) throws Exception {
Method m = ic.getMethod();
Class[] pTypes = m.getParameterTypes();
Object[] pVals = ic.getParameters();
System.out.printf("%s() called on %s\n",
m.getName(),
m.getDeclaringClass().getName());
for (int i = 0; i < pTypes.length; i++) {
System.out.printf("%s = %s\n", pTypes[i], pVals[i]);
}
Object result = ic.proceed();
System.out.printf("Return value: %s\n", result);
return result;
}
}
AuditedInterceptor.java
29
Interceptors (3 of 4)

You must register all interceptor beans in beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
bean-discovery-mode="annotated"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
<interceptors>
<class>demos.cdi.beans.AuditedInterceptor</class>
</interceptors>
</beans>
beans.xml
30
Interceptors (4 of 4)

The last step is to designate which beans (or individual
methods) are to be intercepted
@RequestScoped
@Audited
public class SqlRepository5 implements Repository {
@Override
public String getRecord(int id) {
return "This is record " + id;
}
}
SqlRepository5.java
31
Decorators

Decorators decorate all interfaces they implement
•
•

@Delegate is used to inject the original object
Decorators must be explicitly listed in beans.xml, in their
respective order
Example
@Decorator
public class LogDecorator implements Logger {
@Inject
@Delegate
@Any
private Logger logger;
@Override
public void log(String msg) {
logger.log(timestamp() + ":" + msg);
}
}
32
Using CDI in JSF

There are several issues worth exploring when using CDI
in conjunction with JSF
•
•
•
•

View scope
Initialization vs. post-construction
Accessing query string parameters
Pre-destruction
See the following example files:
•
•
•
demos.cdi.beans.MyViewScopedBean
ViewScopeDemoPage1.xhtml
ViewScopeDemoPage1.xhtml
33
Any Questions?
34