Contents
Introduction
Fundamental Services
* Contexts
– Bind stateful components to lifecycle contexts (i.e. client does not control bean’s lifecycle, container does)
– Lifecycle contexts are well defined and extensible
* Dependency injection
– Inject components into an application in a typesafe way
– Deployment time decision on which implementation of a particular interface to inject
Other Services
* EL (expression language) integration:
– Components can be used directly on JSP/JSF pages
* Decorate injected components
* Associate interceptors with components using typesafe interceptor bindings
* Event notification model
* Added web conversation scope (in addition to request, session, and application)
* Complete SPI spec:
– Clean third party integration
Loose Coupling
* Server/client decoupling via
– Well-defined types and qualifiers (so that server implementation may vary)
* Component lifecycle decoupling via
– Adding context to components
– Automatic life cycle management for components
– Allowing stateful components to interact like services (purely by message passing)
* Message producer/consumer decoupling via events
* Orthogonal concerns decoupling via JEE interceptors
Strong Typing Benefits
* No lookups using string-based names for wiring and correlations (errors can be detected at compile time)
* Allow Java annotation
CDI Beans
* Beans are stateful whose lifecycles are managed by containers, not by bean clients.
Bean Attributes
* Bean Types
– Almost any Java type may be a bean type
* Qualifiers
* Scope
* EL name
* Interceptor bindings
* Implementation
What is a Managed Bean
A managed bean is a top-level Java class if
* Defined to be a managed bean by, for example, JSF spec.
* Or meets all the following conditions:
– It is not a nonstatic inner class
– It is a concrete class or is annotated @Decorator
– It is not annotated with an EJB component-defining annotation or declared as an EJB bean class in ejb-jar.xml
– It has an appropriate constructor:
1) a constructor with no parameters
2) a constructor annotated @Inject
Injectable Objects
* Any Java class (almost: what’s not?)
* Session Beans
* JEE resources: data sources, JMS topics/queues/connection factories
* Persistence contexts (JPA EntityManager objects)
* Producer fields
* Objects returned by producer methods
* Web service references
* Remote EJB references
Alternatives
* Annotate a bean implementation as Alternative
public @Alternative class MockPaymentProcessor extends PaymentProcessorImpl { ... }
* Specify to use alternative implementation in beans.xml
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> <alternatives> <class>org.mycompany.mock.MockPaymentProcessor</class> </alternatives> </beans>
Interceptors
* An interceptor binding type is a user-defined annotation that is itself annotated @InterceptorBinding.
* It lets us bind interceptor classes to bean classes with no direct dependency between the two classes.
* Interceptors are disabled by default. Use beans.xml to enable interceptor and order interceptors.
* Define an interceptor binding type:
@InterceptorBinding @Inherited @Target( { TYPE, METHOD }) @Retention(RUNTIME) public @interface Transactional {}
* Implement the interceptor binding type:
public @Transactional @Interceptor class TransactionInterceptor { ... }
* Apply the interceptor to a bean:
public @SessionScoped @Transactional class ShoppingCart implements Serializable { ... }
Using Qualifiers
* A qualifier is an annotation that you apply to a bean
* A qualifier type is a Java annotation defined as
@Target({METHOD, FIELD, PARAMETER, TYPE})
@Retention(RUNTIME)
* Used to provide various implementations of a particular bean type.
* All non qualifier annotated class are automatically annotated with @Default
* Example:
package greetings; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.RUNTIME; import java.lang.annotation.*; import javax.inject.Qualifier; @Qualifier @Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER}) public @interface Informal {}
* Use the new Qualifier:
package greetings; @Informal public class InformalGreeting extends Greeting { public String greet(String name) { return "Hi, " + name + "!"; } }
Using Qualifier with Members
* Define a qualifier with member, e.g. TestUser :
@Qualifier @Retention(RUNTIME) @Target({ TYPE, METHOD, FIELD, PARAMETER }) public @interface TestUser { UserId userId() default UserId.user1; }
* Use UserId enum class to define available user ids:
public enum UserId { user1, user2; }
* User Provider class to produce test User instances:
public class TestUserProvider { @Produces @TestUser(userId=UserId.user1) public User getUser1(){ User user = new User("user1"); return user; } @Produces @TestUser(userId=UserId.user2) public User getUser1(){ User user = new User("user2"); return user; }
* Inject
@Inject @TestUser(userId = UserId.user1) User user;
Injecting Beans
* Inject a @Default Greeting object:
import javax.inject.Inject; public class Printer { @Inject Greeting greeting; ... }
* Inject a @Informal Greeting object:
import javax.inject.Inject; public class Printer { @Inject @Informal Greeting greeting; ... }
Using Scopes
* CDI introduces two additional scopes, i.e. Dependent and Conversion:
@RequestScoped @SessionScoped @ApplicationScoped @Dependent @ConversationScoped
* Example:
import javax.inject.Inject; import javax.enterprise.context.RequestScoped; import javax.inject.Named; @Named("printer") @RequestScoped public class Printer { @Inject @Informal Greeting greeting; ... }
Producer Methods
* Producer methods provide a way to inject objects that
– are not beans (e.g. a number)
– whose values may vary at runtime
– that require custom initialization (let application take full control of bean instantiation process)
* Example:
– Define producer method:
private int maxNumber = 100; ... @Produces @MaxNumber int getMaxNumber() { return maxNumber; }
– Inject in another managed bean will initialize maxNumber to 100:
@Inject @MaxNumber private int maxNumber;
Obtain Bean Programmatically
* Get a bean factory:
@Inject Instance<PaymentProcessor> paymentProcessorSource;
* Get a bean factory using qualifier:
@Inject @Asynchronous Instance<PaymentProcessor> paymentProcessorSource;
* Get the bean
PaymentProcessor p = paymentProcessorSource.get();
InjectionPoint object
* Used to access metadata relating to the injection point to which it belongs
* Example
– Declare a LogFactory class to produce a Logger object with appropriate class name:
public class LogFactory implements Serializable { private static final long serialVersionUID = 5266112323136335431L; @Produces Logger createLogger(InjectionPoint injectionPoint) { String name = injectionPoint.getMember().getDeclaringClass() .getName(); Logger log = Logger.getLogger(name); return log; } }
– Use following in code to automatically obtain class name:
@Inject Logger log;
– Above is equivalent to:
Logger log = Logger.getLogger(MyClass.class.getName());
– For example,
import mil.osd.dmdc.diss.test.util.WeldJUnit4Runner; import org.apache.log4j.Logger; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(WeldJUnit4Runner.class) public class TestLogger { @Inject Logger log; // Note that TestLogger2 has to be injected. // In another word this won't work: TestLogger2 l2 = new TestLogger2(); l2.testLog(); @Inject TestLogger2 l2; @Test public void testLogger() { log.debug("Test logger..."); } @Test public void testLogger2() { l2.testLog(); } }
import javax.inject.Inject; import org.apache.log4j.Logger; public class TestLogger2 { @Inject Logger log; public void testLog(){ log.debug("TestLogger2..."); } }
Configure CDI App
* Must have beans.xml in
– META-INF (EJB modules or JAR files)
– or WEB-INF (web app): avoid this.
– or WEB-INF/classes/META-INF (web app)
References
* The Java EE 6 Tutorial: Basic Concepts, Fourth Edition By: Eric Jendrock et al Chapter 17
* Weld – JSR-299 Reference Implementation
* To inject or not to inject: CDI is the question
* Dependency Injection – An Introductory Tutorial – Part 1