Date post: | 04-Jul-2015 |
Category: |
Documents |
Upload: | jerome-dochez |
View: | 226 times |
Download: | 1 times |
<Insert Picture Here>
Contexts and Dependency Injection for Java EE
Jérome DochezGlassFish Architect
The following is intended to outline our general product direction. It is intended for information purposes, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions.
The development, release, and timing of any features or functionality described for Oracle's products remains at the sole discretion of Oracle.
What is JSR 299
JSR-299 defines a unifying dependency injection and contextual lifecycle model for Java EE 6• a completely new, richer dependency management model• designed for use with stateful objects – integrates the “web”
and “transactional” tiers – makes it much easier to build applications using JSF and EJB together
• includes a complete SPI allowing third-party frameworks to integrate cleanly in the EE 6 environment
What can be injected
• Certain kinds of things pre-defined by the specification:– (Almost) any Java class– EJB session beans– Objects returned by producer methods– Java EE resources (Datasources, JMS topics/queues, etc)– Persistence contexts (JPA EntityManager)– Web service references– Remote EJBs references
• An SPI allows third-party frameworks to introduce new kinds of things
Simple Example
• A really simple Java class:
public class Greeting { public String greet(String name) { return “hello “ + name; }}
Bean Types
• A Bean type can be almost any Java type• The example below has 4 bean types
public class Bookshop extends Business
implements Shop<Book> {...}
• Yes 4 ! Bookshop, Business, Shop<Book> and Object...• Restrict bean types with @Typed annotation
Bean Constructor
• Bean constructor are identified with the @Inject annotation :
public class ShoppingCart {
final private User user;
@Inject public ShoppingCart(User customer) { user = customer; }}
Field Injection
• A simple client:
public class Printer {
@Inject Greeting greeting; public void greet() {
System.out.println( greeting.greet(“world”) );
}
}
Constructor Injection
public class Printer {
private final Greeting greeting;
@Inject public Printer(Greeting greeting) { this.greeting = greeting; }
public void greet() { System.out.println( greeting.greet(“world”) ); }
}
Method Injection
public class Printer { private Greeting greeting; @Inject void init(Greeting greeting) { this.greeting = greeting; }
public void greet() { System.out.println( greeting.greet(“world”) ); }
}
Producer methods
• A producer method acts as a source of objects to be injected
• Use the @Produces annotation
Public class Shop {
@Produces PaymentProcessor getPaymentProcessor(); @Produces List<Product> getProducts();}
Qualifiers
A qualifier is an annotation that lets a client choose between multiple implementations of a certain type (class or interface)• Qualifiers replace lookup via string-based names• @Default is the default qualifier
Defining new Qualifier
To define a new qualifier :• Write a new annotation• Annotate it with @Qualifier
@Qualifier
@Retention(RUNTIME) @Target({TYPE, METHOD, FIELD, PARAMETER})
public @interface Informal {}
Specifying qualifiers
• On injected field :
@Inject @Informal Greeting greeting;• In method or constructor parameter
public void setGreeting(@Informal Greeting greeting)
Scope and Context
Extensible context model• A scope type is an annotation• A context implementation can be associated with the
scope type
Dependent scope, @Dependent• this is the default• it means that an object exists to serve exactly one
client, and has the same lifecycle as that client
Built-in Scopes
Any web request, web service request, RMI call, EJB timeout:• @ApplicationScoped• @RequestScoped
Any servlet, JSF requests:• @SessionScoped• @ConversationScoped
Custom scopes – provided by third-party frameworks via an SPI
Scoped Objects
• A session scoped object
@SessionScoped
public class Login { private User user;
public void login() { user = … }
public User getUser() { return user; }}
Injecting a scoped object
public class Printer {
@Default Greeting greeting;
@SessionScoped Login login;
public void greet() {
System.out.println(
greeting.greet(
login.getUser().getName() ) ); }
}
Producing a scoped object
• Annotate the bean with the scope annotation
@SessionScopedpublic class Login { private User user;
@Produces User getCurrrentUser() {
... }}
• Injectable as @Inject @SessionScoped User user
Producing a scoped object
• Annotate the producer with the scope annotation
@RequestScopedpublic class Login { private User user;
@Produces @SessionScoped User getCurrrentUser() {
... }}
• Injectable as @Inject @SessionScoped User user
Producer fields
Producer fields are just a shortcut:
public class Login {
@Produces @SessionScoped User user;
public void login() { user = ...; }}
Custom scopes
• Create an annotation for the custom scope – @Target({TYPE, FIELD, METHOD})– @Retention(Runtime)– @Scope or @NormalScope
@Inherited@NormalScope@Target({TYPE, METHOD, FIELD})@Retention(RUNTIME)public @interface BusinessProcessScoped {...}
Names
To use our class in Unified EL expressions, give it a name:
@Named(“printer”)
public class Printer { @Current Greeting greeting;
public void greet() {
System.out.println(
greeting.greet(“world”) );
}
}
Unified EL
• Now we can use the object in a JSF or JSP page:
<h:commandButton value=”Say Hello” action=”#{printer.greet}”/>
<h:outputText value=”#{products.total}”/>
Stateful class
If we want our object to hold state, we need to declare the scope of that state:
@RequestScoped @Named public class Printer {
@Inject Greeting g; private String name;
public void setName(String name) { this.name=name; } public String getName() { return name; }
public void greet() {
System.out.println(g.greet(name) );
}}
Unified EL
• And now we can use it to process a JSF form:
<h:form> <h:inputText value=”#{printer.name}”/> <h:commandButton value=”Say Hello” action=”#{printer.greet}”/></h:form>
• Or a JSP :
name : ${printer.name}
Events
• Beans may produce and consume events• Event is :
– A Java object – the event object– A (possibly empty) set of qualifiers types
public interface Event<T> { public void fire(T event); public Event<T> select(Annotation...
qualifiers); ... more select...}
Event producer
• Beans fire event via an Event instance
@Inject@AdminEvent<LoggedInEvent> loggedInEvent;
• Use the fire() method to send the events
public void login() { ... loggedInEvent.fire( new LoggedInEvent(user);}
Observer Method
• Use the @Observes annotation
public void afterLogin(@Observes LoggedInEvent event) {
....}
• Or use some qualifiers
public void afterLogin(@Observes @Admin LoggedInEvent event) {
....}
Interceptor Binding Types
• Interceptors are used to separate cross-cutting concerns from business logic
• Can be enabled or disabled at runtime• Interceptor binding type is an annotation annotated with
InterceptorBinding
@Inherited@InterceptorBinding@Target({TYPE, METHOD})@Retention(RUNTIME)public @interface Transactional {...}
Bindings for an interceptor
• Interceptor bindings are specified by annotating the interceptor class with– The binding type (here it's @Transactional)– The Interceptor annotation
@Transactional@Interceptorpublic class TransactionInterceptor {
@AroundInvoke public Objet manageTx(InvocationContext
ctx) throws Exception {...}}
Binding an interceptor
• Annotate with the interceptor binding type a bean class :
@Transactionalpublic class ShoppingCart {
// all business methods are transactional}
• Or just a method : Public class ShoppingCart { @Transactional public void placeOrder() {...}}
Decorators
• Similar to interceptors but only apply to a particular Java type.– Can be easily enabled or disabled at runtime– Strong semantic binding between the decorator and decorated
public interface Persistence<T> {
void save(T object); T load();}
Decorator definition
• Annotate with Decorator annotation
@Decorator public class AuthPersistence<T> implements Persistence<T> {
@Inject @Delegate Persistence<T> delegate;
public void save(T object) { authorize(); delegate.save(object); }}
Stereotypes
• It is not only interceptor bindings we want to reuse!• We have common architectural “patterns” in our
application, with recurring component roles– Capture the roles using stereotypes
• A stereotype packages:– A default scope – A set of interceptor bindings – A default scope– Defaulted bean EL names
Simple Action Stereotype
@Stereotype@Target(TYPE)@Retention(RUNTIME)@Secure@RequestScoped@Transactionalpublic @interface Action {...}
optional annotations in orange
Using a stereotype
• Annotating a Bean
@Actionpublic class Greeting {
public String greet(String name) { return “hello “ + name; }}
Resources
• To inject Java EE resources, persistence contexts, web service references, remote EJB references, etc, use a producer field :
public class UserDatabasePersistenceContext { @Produces @UserDatabase @PersistenceContext EntityManager userDatabase;}
Resources
• @Resource possible to specify the jndi name
public class PricesTopic { @Produces @Prices @Resource(
name=“java:global/env/jms/Prices”) Topic pricesTopic;
}
Injecting resources
• Now we’ve eliminated the use of string-based names:
public class UserDatabasePersistenceContext { @UserDatabase EntityManager userDatabase;
}
public class PricesTopic {
@Prices TopicSession topicSession; @Prices TopicPublisher topicPublisher;}
More information
• JCP specificationhttp://www.jcp.org/en/jsr/detail?id=299
• GlassFish V3 Java EE 6 Reference Implementation
http://glassfish.dev.java.net• The Aquarium
http://blogs.sun.com/theaquarium