Here is the presentation

advertisement
CDI – Contexts and Dependency
Injection for the JavaEE platform
(JSR299)
Bozhidar Bozhanov
Bulgarian Association of Software Developers
www.devbg.org
About me
• Senior Java Developer at Fish4
• 3+ years experience with Spring and
dependency injection
• Implementor of JSR-299 as a university project
• Committer at Hector (Java Cassandra API)
• http://techblog.bozho.net
Dependency injection?
• Classes define what are their dependencies, not
how they obtain them
• Object dependencies are set externally
• Unit-test and mocking friendly
• DI frameworks - objects are managed and have
a lifecycle
History
• Theoretical basis - GoF Hollywood principle;
Steffano Mazzocchi
• Spring – 2002/2003, Rod Johnson
• Pico Container - 2003
• Martin Fowler popularized the term - 2004
• JBoss Seam, Google Guice, EJB 3.0
• Contexts and Dependency Injection (JSR-299,
JavaEE 6) - 2006-2009
Current problems
• Problematic integration between JavaEE
components
• „Crippled“ dependency-injection in EJB
• No standard – only propriatary DI frameworks
(spring, guice, seam)
• Extended reliance on string qualifiers (no
compile-time safety)
JSR-299
• What's a JSR?
• CDI Initially named „Web Beans“
• Expert Group formed in June 2006, spec-lead is
Gavin King
• Early draft (2007), Public review (2008), Final
draft (mid-2009), Ralease (Dec 2009)
• Bob Lee (Guice) left the expert group
• IBM voted „No“, Google voted „Yes“, VMware
(SpringSource) and Eclipse didn't vote.
What is CDI
• Type-safe DI framework (based on Seam, Guice
and Spring)
• Uses JSR-330 (Dependency Injection for Java),
lead by Rod Johnson (Spring) and Bob Lee
(Guice), which defines only DI annotations (for
JavaSE)
• DI JavaEE-wide – JSF managed beans, EJB,
JavaEE Resources
Implementations; web profile
• Three implementations: JBoss Weld, Apache
OpenWebBeans and Resin CanDI
• Only one stable at the moment – Weld, used in
Glassfish v3 and JBoss AS (5.2, 6)
• JavaEE 6 has the so-called „profiles“. CDI is part
of the „Web profile“
• CDI implementations are not limited to
application servers (with the help of extensions)
Java EE structure with CDI
Beans and bean archives
• A bean archive has META-INF/beans.xml
• All classes within a bean archive are beans, and
eligible for injection
• All classes in outside bean archives are not
beans
• Beans can have type(s), scope, EL name,
qualifiers, interceptors.
• Beans can be JSF beans, EJBs, JavaEE
resources
Injection
• @javax.inject.Inject is used:
public class OrdersBean {
@Inject private OrdersDao dao;
}
• The „dao“ field is called „injection point“.
Injection point types are:
• Field
• Constructor
• Setter
• Initializer
Injection points
public class OrdersBean {
@Inject private OrdersDao dao;
@Inject
public OrdersBean(OrdersDao dao){}
@Inject
public void init(OrdersDao dao) {}
@Inject
public void setOrdersDao(OrdersDao dao){}
}
Injection targets
• Inject into:
– POJOs
– EJB Session Beans
– Servlets
• Injection candidates:
– POJOs
– EJB Session Beans
– JavaEE Resources
Bean scopes
• Built-in scopes (normal vs pseudo):
• @ApplicationScoped – i.e. Singleton
• @RequestScoped – created on http request
• @SessionScoped – within a HttpSession
• @ConversationScoped – between request
and session
• @Dependent (default, pseudo) – the object
lives as long as the object it is injected into
• Custom scopes
Bean name
• @Named("beanName"). Defaults to the
decapitalized, simple name of the class
• Used in EL expressions:
<h:outputText
value="#{orderBean.order.price}" />
• Used in injections (discouraged)
@Inject @Named("ordersBean")
private OrdersBean orderBean;
Qualifiers
• Qualifiers are annotations (unlike in spring):
@Qualifier //retention & target ommitted
public @interface Synchronous {}
• Qualifiers are used to differentiate beans with the same
type:
@Synchronous
public class SynchronousCreditCardProcessor
implements CreditCardProcessor {..}
@Asynchronous
public class AsyncCreditCardProcessor
implements CreditCardPRocessor {..}
@Inject @Synchronous
private CreditCardProcessor processor;
Built-in qualifiers
• @Any – all beans have this, unless they have @New
• @Default, @Named
• @New – forces the container to return a new bean
instance each time
@New public class SomeBean {..}
public class AnotherBean {
@Inject SomeBean bean1;
@Inject SomeBean bean2;
@PostConstruct void init() {
// false
System.out.println(bean1 == bean2);
}
}
Stereotypes
• Stereotypes are used to reduce the amount
of boilerplate code:
@Stereotype //denoting a stereotype
@Named // built-in qualifier
@RequestScoped // scope
public @interface RequestScopedSecureBean
{}
@RequestScopedNamed Bean
public class OrdersBean {..}
Demo
(Beans, Injection, Qualifiers, Stereotypes, EL)
Producers
• A way to utilize complex construction
• Allow non-beans to be injected (i.e. 3rd party
classes outside a bean-archive)
• Handles object disposal
//this class is within a bean archive
class ConnectionProducer {
@Produces Connection createConnection() {
// create and return jdbc connection
}
// when the object gets out of scope
void dispose(@Disposes Connection con) {
con.close();
}
}
Producer fields
• Allow injecting JavaEE resources:
@Produces @SomeTopic
@Resource(name="topics/SomeTopic")
private Topic someTopic;
@Produces
@PersistenceContext
private EntityManager entityManager;
@Produces // non-JaveEE producer field
private Some3rdPartyBean bean =
new Some3rdPartyBean();
Injection point metadata
• Gives information about the injection point
@Produces Logger createLogger(InjectionPoint
injectionPoint) {
return Logger.getLogger(injectionPoint
.getMember().getDeclaringClass());
}
@Produces @HttpParam("")
String getParamValue(ServletRequest request,
InjectionPoint ip) {
return request.getParameter(ip
.getAnnotation(HttpParam.class).value());
}
}
Decorators
• Decorators decorate all interfaces they
implement
• @Delegate is used to inject the original
object
• Decorators must be explicitly listed in
beans.xml,
@Decorator in their respective order
classcan
LogDecorator
implements Logger
• public
Decorators
be abstract
@Delegate @Any private Logger logger;
@Override
public void log(String msg) {
logger.log(timestamp() + ":" + msg);
}
}
{
Interceptors
• Interceptor bindings (can be nested or included
in stereotypes)
@InterceptorBinding // + retention & target
public @interface Transactional{}
@InterceptorBindings @Transactional
public @interface DataAccess {}
• Declaring the actual interceptor:
@Transactional @Interceptor
public class TransactionInterceptor {
@AroundInvoke
public Object manage(InvocationContext ctx)
throws Exception { .. }
}
Interceptors (2)
• Declaring the interceptor on the target bean
@Transactional //all methods are transactional
public class OrderService { .. }
• Like decorators, must be enabled in beans.xml
• Interceptors-to-intercepted targets: many-tomany
• Interceptors-to-interceptor bindings: many-tomany
• Binding vs @NonBinding interceptor attributes
Demo
(Producers, Decorators, Interceptors)
Programmatic lookup
• When qualifiers are to be examined at
runtime:
@Inject @Any
private Instance<CreditCardProcessor> ccProc;
public void processPayment(
Payment payment, boolean synchronously) {
Annotation qualifier = synchronously
? new SynchronousLiteral()
: new AsynchronousLiteral();
CreditCardProcessor actualProcessor =
ccProc.select(qualifier).get();
actualProcessor.process(payment);
}
class SynchronousLiteral extends
AnnotationLiteral<Synchronous> {}
Events
• Event producer, making use of generics:
@Inject @EventQualifier
private Event<SampleEvent> event;
public void fireEvent() {
event.fire(new SimpleEvent());
}
• Event observer (with the appropriate qualifier)
public void observes(
@Observes @EventQualifier
SampleEvent event) { .. }
}
Events (2)
• Dynamic choice of qualifiers
@Inject @Any Event<LoggedEvent> loggedEvent;
public void login(user) {
LoggedEvent event = new LoggedEvent(user);
if (user.isAdmin()) {
loggedEvent.select(
new AdminLiteral()).fire(event);
} else {
loggedEvent.fire(event);
}
}
• @Observes(notifyObserver=IF_EXISTS)
notifies only if an instance of the declaring
bean
Circular dependencies
• CDI implementations must use proxies for all
scopes, except @Dependent
@ApplicationScoped
public class Bean1 {
@Inject
public Bean1(Bean2 bean2) {..}
}
@ApplicationScoped
public class Bean2 {
@Inject
public Bean2(Bean1 bean1) {..}
}
Demo
(Programatic lookup, Events, Circular Dependencies)
Portable extensions
• CDI allows plugable extensions that can access
the context, hook to context events
• Providing its own beans, interceptors and
decorators to the container
• Injecting dependencies into its own objects using
the dependency injection service
• Providing a context implementation for a custom
scope
• Augmenting or overriding the annotation-based
metadata with metadata from some other source
Portable extensions (2)
• http://seamframework.org/Weld/PortableExtensio
nsPackage
• XML configuration
• Wicket integration
• JavaSE and Servlet container support
Concerns
• Lack of standardized XML configuration
• Not many „extras“ available yet
• Annotation mess
• CDI interceptors might not be sufficient,
compared to Spring AOP (AspectJ syntax)
• (un)portable extensions may become exactly
what spring is being critized for – size and
complexity
• Complex
• Being a standard?
Resources
• http://seamframework.org/service/File/105766
• http://www.slideshare.net/johaneltes/java-ee6-cdi
• http://www.slideshare.net/mojavelinux/jsr299-cdiweld-the-future-of-seam-javaone-2010
• http://download.oracle.com/javaee/6/tutorial/doc/
gjbnz.html
Questions?
Download