contexts and dependency injection for the javaee platform
DESCRIPTION
TRANSCRIPT
CDI – Contexts and CDI – Contexts and Dependency Injection for the Dependency Injection for the JavaEE platform (JSR299)JavaEE platform (JSR299)
Bozhidar BozhanovBulgarian Association of Software Developers
www.devbg.org
About meAbout 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?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
HistoryHistory
• 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 problemsCurrent 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-299JSR-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 CDIWhat 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 profileImplementations; 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 CDIJava EE structure with CDI
Beans and bean archivesBeans 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
• @javax.inject.Inject is used:@javax.inject.Inject is used:
InjectionInjection
publicpublic classclass OrdersBean { OrdersBean {@Inject@Inject privateprivate OrdersDao OrdersDao daodao;;
}}
• The „dao“ field is called „injection point“. The „dao“ field is called „injection point“. Injection point types are:Injection point types are:
• FieldField• ConstructorConstructor• SetterSetter• Initializer Initializer
Injection pointsInjection points
publicpublic classclass OrdersBean { OrdersBean { @Inject@Inject privateprivate OrdersDao OrdersDao daodao;;
@Inject@Inject publicpublic OrdersBean(OrdersDao dao){} OrdersBean(OrdersDao dao){}
@Inject@Inject publicpublic voidvoid init(OrdersDao dao) {} init(OrdersDao dao) {}
@Inject@Inject publicpublic voidvoid setOrdersDao(OrdersDao dao){} setOrdersDao(OrdersDao dao){}}}
• Inject into:Inject into:– POJOsPOJOs– EJB Session BeansEJB Session Beans– ServletsServlets
• Injection candidates:Injection candidates:– POJOsPOJOs– EJB Session BeansEJB Session Beans– JavaEE ResourcesJavaEE Resources
Injection targetsInjection targets
Bean scopesBean 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
• @Named(@Named(""beanNamebeanName"")). Defaults to the . Defaults to the decapitalized, simple name of the classdecapitalized, simple name of the class
• Used in EL expressions:Used in EL expressions:
Bean nameBean name
<<h:outputTexth:outputText valuevalue=="#{orderBean.order.price}""#{orderBean.order.price}" />/>
• Used in injections (discouraged)Used in injections (discouraged)@Inject@Inject @Named@Named(("ordersBean""ordersBean"))privateprivate OrdersBean OrdersBean orderBeanorderBean;;
• Qualifiers are annotations (unlike in spring):Qualifiers are annotations (unlike in spring):
QualifiersQualifiers
@Qualifier //retention & target ommitted@Qualifier //retention & target ommittedpublicpublic @interface@interface SynchronousSynchronous {} {}
• Qualifiers are used to differentiate beans with the same Qualifiers are used to differentiate beans with the same type:type:
@@Inject Inject @@Synchronous Synchronous privateprivate CreditCardProcessor processor; CreditCardProcessor processor;
@@SynchronousSynchronouspublicpublic class class SynchronousCreditCardProcessorSynchronousCreditCardProcessor implementsimplements CreditCardProcessor {..} CreditCardProcessor {..}@@AsynchronousAsynchronouspublicpublic classclass AsyncCreditCardProcessor AsyncCreditCardProcessor implementsimplements CreditCardPRocessor {..} CreditCardPRocessor {..}
• @Any@Any – all beans have this, unless they have – all beans have this, unless they have @New@New• @Default, @Named@Default, @Named• @New @New – – forces the container to return a new bean forces the container to return a new bean instance each timeinstance each time
Built-in qualifiersBuilt-in qualifiers
@@New New publicpublic classclass SomeBean {..} SomeBean {..}
publicpublic classclass AnotherBean { AnotherBean { @@Inject SomeBean bean1;Inject SomeBean bean1; @@Inject SomeBean bean2; Inject SomeBean bean2; @@PostConstruct PostConstruct voidvoid init() { init() { // false// false System.out.println(bean1 == bean2);System.out.println(bean1 == bean2); }}}}
• Stereotypes are used to reduce the amount Stereotypes are used to reduce the amount of boilerplate code:of boilerplate code:
StereotypesStereotypes
@@Stereotype Stereotype //denoting a stereotype//denoting a stereotype@@Named Named // built-in qualifier// built-in qualifier@@RequestScoped RequestScoped // scope// scopepublicpublic @interface@interface RequestScopedSecureBean {}RequestScopedSecureBean {}
@@RequestScopedNamedRequestScopedNamed BeanBeanpublicpublic classclass OrdersBean {..} OrdersBean {..}
DemoDemo(Beans, Injection, Qualifiers, Stereotypes, EL)
• A way to utilize complex constructionA way to utilize complex construction• Allow non-beans to be injected (i.e. 3Allow non-beans to be injected (i.e. 3rdrd party party classes outside a bean-archive)classes outside a bean-archive)• Handles object disposalHandles object disposal
ProducersProducers
//this class is within a bean archive//this class is within a bean archiveclassclass ConnectionProducer { ConnectionProducer { @Produces@Produces Connection createConnection() { Connection createConnection() { // create and return jdbc connection// create and return jdbc connection }} // when the object gets out of scope // when the object gets out of scope voidvoid dispose( dispose(@Disposes@Disposes Connection con) { Connection con) { con.close();con.close(); }}}}
• Allow injecting JavaEE resources:Allow injecting JavaEE resources:
Producer fieldsProducer fields
@@Produces Produces @@SomeTopicSomeTopic@@Resource(name=Resource(name="topics/SomeTopic""topics/SomeTopic"))privateprivate Topic someTopic; Topic someTopic;
@@ProducesProduces@@PersistenceContextPersistenceContextprivateprivate EntityManager entityManager; EntityManager entityManager;
@@Produces Produces // non-JaveEE producer field// non-JaveEE producer fieldprivateprivate Some3rdPartyBean bean = Some3rdPartyBean bean = newnew Some3rdPartyBean(); Some3rdPartyBean();
• Gives information about the injection pointGives information about the injection point
Injection point metadataInjection point metadata
@@Produces Logger createLogger(InjectionPointProduces Logger createLogger(InjectionPoint injectionPoint) { injectionPoint) { returnreturn Logger.getLogger(injectionPoint Logger.getLogger(injectionPoint .getMember().getDeclaringClass()); .getMember().getDeclaringClass()); }}
@Produces@Produces @@HttpParam(HttpParam(""""))String getParamValue(ServletRequest request, String getParamValue(ServletRequest request, InjectionPoint ip) {InjectionPoint ip) { returnreturn request.getParameter(ip request.getParameter(ip .getAnnotation(HttpParam..getAnnotation(HttpParam.class)class).value());.value()); }}}}
• Decorators decorate all interfaces they Decorators decorate all interfaces they implementimplement• @Delegate @Delegate is used to inject the original is used to inject the original objectobject• Decorators must be explicitly listed in Decorators must be explicitly listed in beans.xml, in their respective orderbeans.xml, in their respective order• Decorators can be abstractDecorators can be abstract
DecoratorsDecorators
@@DecoratorDecoratorpublicpublic classclass LogDecorator LogDecorator implementsimplements Logger { Logger { @@Delegate Delegate @@Any Any privateprivate Logger Logger loggerlogger;; @Override@Override publicpublic voidvoid log(String msg) { log(String msg) { loggerlogger.log(timestamp() + .log(timestamp() + ":"":" + msg); + msg); }}}}
• Interceptor bindings (can be nested or included Interceptor bindings (can be nested or included in stereotypes)in stereotypes)
InterceptorsInterceptors
@@InterceptorBinding InterceptorBinding // + retention & target// + retention & targetpublicpublic @interface@interface TransactionalTransactional{}{}
@@InterceptorBindings @TransactionalInterceptorBindings @Transactionalpublicpublic @interface@interface DataAccessDataAccess {} {}
• Declaring the actual interceptor:Declaring the actual interceptor:@@Transactional Transactional @@InterceptorInterceptorpublicpublic classclass TransactionInterceptor { TransactionInterceptor { @@AroundInvokeAroundInvoke publicpublic Object manage(InvocationContext ctx) Object manage(InvocationContext ctx) throwsthrows Exception { .. } Exception { .. }}}
• Declaring the interceptor on the target beanDeclaring the interceptor on the target bean
Interceptors (2)Interceptors (2)
@@Transactional Transactional //all methods are transactional//all methods are transactionalpublic classpublic class OrderService { .. } OrderService { .. }
• Like decorators, must be enabled in beans.xmlLike decorators, must be enabled in beans.xml• Interceptors-to-intercepted targets: many-to-Interceptors-to-intercepted targets: many-to-manymany• Interceptors-to-interceptor bindings: many-to-Interceptors-to-interceptor bindings: many-to-manymany• Binding vs Binding vs @NonBinding@NonBinding interceptor attributes interceptor attributes
DemoDemo(Producers, Decorators, Interceptors)
Programmatic lookupProgrammatic lookup
@@Inject Inject @@AnyAnyprivateprivate Instance<CreditCardProcessor> ccProc; Instance<CreditCardProcessor> ccProc;public voidpublic void processPayment( processPayment( Payment payment, Payment payment, booleanboolean synchronously) { synchronously) { Annotation qualifier = synchronouslyAnnotation qualifier = synchronously ? ? newnew SynchronousLiteral() SynchronousLiteral() : : newnew AsynchronousLiteral(); AsynchronousLiteral(); CreditCardProcessor actualProcessor =CreditCardProcessor actualProcessor = ccProc.select(qualifier).get();ccProc.select(qualifier).get(); actualProcessor.process(payment);actualProcessor.process(payment);}}
classclass SynchronousLiteral SynchronousLiteral extendsextends AnnotationLiteral<Synchronous> {}AnnotationLiteral<Synchronous> {}
• When qualifiers are to be examined at When qualifiers are to be examined at runtime:runtime:
EventsEvents
@@Inject Inject @@EventQualifierEventQualifierprivateprivate Event<SampleEvent> event; Event<SampleEvent> event;
publicpublic voidvoid fireEvent() { fireEvent() { event.fire(new SimpleEvent());event.fire(new SimpleEvent());}}
• Event observer (with the appropriate qualifier)Event observer (with the appropriate qualifier)
publicpublic voidvoid observes( observes( @@Observes Observes @@EventQualifierEventQualifier SampleEvent event) { .. }SampleEvent event) { .. }}}
• Event producer, making use of generics:Event producer, making use of generics:
Events (2)Events (2)
@@Inject Inject @@Any Event<LoggedEvent> loggedEvent;Any Event<LoggedEvent> loggedEvent;publicpublic voidvoid login(user) { login(user) { LoggedEvent event = LoggedEvent event = new new LoggedEvent(user);LoggedEvent(user); ifif (user.isAdmin()) { (user.isAdmin()) { loggedEvent.select(loggedEvent.select( newnew AdminLiteral()).fire(event); AdminLiteral()).fire(event); } } elseelse { { loggedEvent.fire(event);loggedEvent.fire(event); }}}}
• Dynamic choice of qualifiersDynamic choice of qualifiers
• @Observes(notifyObserver=IF_EXISTS)@Observes(notifyObserver=IF_EXISTS)notifies only if an instance of the declaring notifies only if an instance of the declaring bean bean exists in the current contextexists in the current context
Circular dependenciesCircular dependencies
@@ApplicationScopedApplicationScopedpublicpublic classclass Bean1 { Bean1 { @@InjectInject publicpublic Bean1(Bean2 bean2) {..} Bean1(Bean2 bean2) {..}}}
@@ApplicationScopedApplicationScopedpublicpublic classclass Bean2 { Bean2 { @@InjectInject publicpublic Bean2(Bean1 bean1) {..} Bean2(Bean1 bean1) {..}}}
• CDI implementations must use proxies for all CDI implementations must use proxies for all scopes, except scopes, except @Dependent@Dependent
DemoDemo(Programatic lookup, Events, Circular Dependencies)
Portable extensionsPortable 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)Portable extensions (2)• http://seamframework.org/Weld/
PortableExtensionsPackage• XML configuration• Wicket integration• JavaSE and Servlet container support
ConcernsConcerns• 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?
• http://seamframework.org/service/File/105766• http://www.slideshare.net/johaneltes/java-ee6-cd
i• http://www.slideshare.net/mojavelinux/jsr299-cdi-
weld-the-future-of-seam-javaone-2010• http://download.oracle.com/javaee/6/tutorial/doc/
gjbnz.html
ResourcesResources
QuestionsQuestions??