Welcome everyone on talk When Camel meets CDI. On slide you see that word “when" is stroke. It was removed because Camel already met CDI. :) Now we can share our experiences with you.
For this talk I have few goals. As this talk is latest in “Camel in Action” track you might get some points which was pointed by other presenters. First of all, I would like to determine state of Dependency Injection in Camel. It is ready for other than regular DI containers or not? We will point also possible extension points which are already present in Camel. This point might be really useful for people involved in other projects. You will see how to prepare hooks inside your projects to let developers use preferred DI container. Finally I will show you how transition from Spring to CDI looks like. But before we will go there, please let me introduce myself.
My name is Lukasz Dywicki. I was born in Poland in 1985. I am independent software contractor since 2008 and I worked since then with number of companies. My main area of interest is middleware stuff from Apache. I realized in 2008 that there is lots of possibilities to help community and earn some cash. After almost two years I became Apache Karaf commiter. So you can be sure that I am not regular Java EE fan. My natural ground is OSGi. I am also contributor in Apache Camel. I am not yet commiter, however I walk around this project since I started using ServiceMix.
Before you will start thinking what this guy does here? He is not even Camel commiter! I would like to say that CDI extension in Camel is partially done by me and I support it as part of my work for Red Hat.
CDI is something fresh I believe. On this ApacheCon edition this is third talk about this spec. CDI was done as specification under Java Community Process.
CDI as specification is assigned to Java EE, however it don't have to run on EE server. Most popular existing containers supports standalone mode. In other words you can run CDI inside swing application without fear. All injecting stuff is really built on top of JSR330. In fact this spec was standardization of annotations used by Guice and Spring. The JSR330 is limited to only few annotations and only one interface. However it's great basement for doing something more.
On this slide you can see simplest CDI usage on servlet level. From developer point of view most important thing is fact, that there is no need to add anything more. No need to define bean in XML. No need to create any delegator beans or register proxy filter/servlet/listener or whatever. It just works. CDI in this moment became the missing glue. But let's go further.
CDI compared to JSR330 is like big brother. It contains much more features, starting from stereotypes trough scopes, decorators, interceptors up to bean registry. As in other popular dependency containers developers can decide to implement new scope if necessary. It doesn't happen often, but for these who would like there is ready to use API to register it. Next thing, these days a term 'type safe' became very popular. I think it might be another buzz word. ;) So what's the type safety in case of CDI means? That you don't have to rely on bean names. You can use interface and qualifiers to choose interesting implementation. Typically if you have dependencies, container should manage creation of them and CDI does that. Also lifecycle management is done by container for you. Just put @PostConstruct or @PreDestroy annotations on method.
Going further with DI stuff we can start seeing differences to existing containers – CDI discovers beans by default. You don't have to name them or even annotate. To be honest, in 90% that's the case. The beans.xml file located in META-INF for JARs and in WEB-INF for WARs is a marker file. By default CDI container will not scan classpath entries without this file. The extension mechanism is standard, it requires additional entry in META-INF/services and implementation of given interface.
After this short introduction we can determine state of support for Dependency Injection in Camel.
We can divide dependency containers into two categories. XML based or not. Of curse you can use Spring without defining beans in XML, however you still need some switches to be turned on inside application context. Blueprint is totally based on XML, it's OSGi specific standard which grown on top of Spring Dynamic Modules. On second hand we have annotation based stuff. Here we have Guice and Spring JavaConfig.
And CDI. Bigger brother of Guice.
Ok, we spent some time on serious things. Now time to relax a bit!
Ok, we spent some time on serious things. Now time to relax a bit!
Two core parts of Camel which allows to port it across different Dependency Injection containers are Registry and Injector.
Let's take a look on Registry interface. It solves problem with portability of Dependency Injection containers. We can look up beans by name. First method returns an object, second lookup operation allows to set expected bean type. Third is designed to do lookups using only type. It returns Map where key is bean name and value is bean instance.
Camel core ships with following registries. First is for wrapping multiple instances into one. Second is simple map and allows to put object instances to registry without any problems. The JndiRegistry allows to lookup beans using naming context. Latest is most tricky. You might not be aware of, but it's used all the time by Camel. It's doesn't meter if you use properties or not – default camel context will always wrap registry set by you into PropertyPlaceholderDelegateRegistry.
This slide lists registries provided by modules other than core. First comes with camel-spring, second with camel-blueprint. Third is provided by camel-core-osgi. Latest is developed uner camel-cdi module. What is important here – there is no registry provided by Guice. Because construction of Guice there is no possibility to implement something similar to registry. It provides only Injector.
Injector is second tool which lets integrate Dependency Injection containers with Camel. It allows to obtain bean instance using type name only. I know it looks similar to Registry but both are used in different situation. Injector in many cases is used when lookup in Registry fails but given instance of bean is necessary to run. For example if lookup of component in Registry fails Camel tries to resolve type of Component and then use Injector to create instance of given type.
Reflection injector simply creates instance of given class using Reflection API. DefaultInjector populates fields annotated with Camel annotations like Produce or EndpointInject using a magic class called DefaultCamelBeanPostProcessor. To be honest DefaultInjector duplicates work which could be possibly done by Dependency Injection container itself. However Spring API do not have good annotation processing API to stick with. That's
These injectors are in place by default. Mostly used is Spring, then we have Guice and new one – CDI.
Now, after we saw integration points with DI containers, we can start talking about transition from Spring. How it looks like in Camel case.
There are key differences between Spring and CDI. First of all we don't have something like ApplicationContext. There is no pre or post processors and you can not easily do a CamelContextAware stuff. Next things is problems with multiple instances of contexts – in CDI you usually have one instance of given bean. When you have multiple beans you need to link it's dependencies in right way. That's why it becomes more complicated. And finally there is no domain specific namespaces. There is no need for them because there is no XML.
Obtain bean instance from CDI requires few lines more than Spring. In spring you just could call applicationContext getBean method and that was all. In CDI you need to obtain reference first and then use this reference to ask for instance of bean. To avoid code duplication in camel-cdi we simply use deltaspike.
As I said there is no pre/post bean processors in case of CDI. But the good thing is that we could catch events. If we would like to change bean definition we can catch ProcessAnnotatedType event and modify bean definition. This code add @Inject to method setCamelContext using deltaspike AnnotatedTypeBuilder.
For linking route builder together with camel context we use @ContextName annotation. It's just a marker which allows extension link routes written by user with context instances to create.
When Camel meets CDI
When Camel meets CDI Łukasz Dywicki
Goals● Determine state of DI support in Camel● Possible extension points to use● Transition from Spring to CDI● Show running CDI + Camel application
Who am I?● Łukasz Dywicki – Independent software contractor● ServiceMix user since 2008● Commiter of Apache Karaf● Camel contributor
Brief introduction – CDI cont.● CDI contains more elements specific to full featured DI container – Stereotypes – Application/Session/Request Scope – Bean Registry*● Possibility to implement own scopes● Its type safe by definition● Handles dependent beans creation● Lifecycle management with JSR-250
Brief introduction – CDI cont.● Discovery of beans rely on presence of beans.xml file in META-INF or WEB-INF● Container discovers beans automatically● CDI is extensible – Extension interface – META-INF/services entry
Transition from Spring to CDI● No ApplicationContext instance – How do I get bean from it?● No pre/post processors – CamelContextAware● Multiple camel contexts – Linking beans with camel contexts● No domain specific namespaces
How do I get bean● Use Apache DeltaSpike BeanProvider class: – getContextualReference(String) = Object – getContextualReference(Class<T>) = T – getBeanDefinition(Class<T>) = Set<Bean<T>> – getContextualReferences(Class<T>) = List<T>