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?