When Camel meets CDI

Embed Size (px)

Citation preview

ApacheCon Europe 2012 Presentation Template - 1

When Camel meets CDI

ukasz Dywicki

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.

Goals

Determine state of DI support in Camel

Possible extension points to use

Transition from Spring to CDI

Show running CDI + Camel application

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.

Who am I?

ukasz DywickiIndependent software contractor

ServiceMix user since 2008

Commiter of Apache Karaf

Camel contributor

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.

Camel + Red Hat

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.

Brief introduction CDI, JSR-299

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.

Brief introduction CDI

Built on top of JSR-330

Package javax.inject@Inject

@Named

@Qualifier

@Scope

@Singleton

Provider

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.

Brief introduction CDI cont.

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.

Brief introduction CDI cont.

CDI contains more elements specific to full featured DI containerStereotypes

Application/Session/Request Scope

Bean Registry*

Possibility to implement own scopes

It's type safe by definition

Handles dependent beans creation

Lifecycle management with JSR-250

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.

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 extensibleExtension interface

META-INF/services entry

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.

Support for Dependency Injection in Camel

After this short introduction we can determine state of support for Dependency Injection in Camel.

Support for DI in Camel

XML basedSpring

Blueprint

Annotation basedGuice

Spring JavaConfig

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.

Support for DI in Camel

XML basedSpring

Blueprint

Annotation basedGuice

Spring JavaConfig

CDI

And CDI. Bigger brother of Guice.

Some pictures for fun

Ok, we spent some time on serious things. Now time to relax a bit!

Back to Camel

Ok, we spent some time on serious things. Now time to relax a bit!

Support for DI in Camel cont.

Registry

Injector

Two core parts of Camel which allows to port it across different Dependency Injection containers are Registry and Injector.

Registry

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.

Core Registries

CompositeRegistry

SimpleRegistry

JndiRegistry

PropertyPlaceholderDelegateRegistry

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.

3rd Party Registries

ApplicationContextRegistry

BlueprintContainerRegistry

OsgiServiceRegistry

CdiBeanRegistry

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

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.

Core Injectors

ReflectionInjector

DefaultInjector

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

3rd party injectors

SpringInjector

GuiceInjector

CdiInjector

These injectors are in place by default. Mostly used is Spring, then we have Guice and new one CDI.

Transition from Spring to 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.

Transition from Spring to CDI

No ApplicationContext instanceHow do I get bean from it?

No pre/post processorsCamelContextAware

Multiple camel contextsLinking beans with camel contexts

No domain specific namespaces

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.

How do I get bean

Use Apache DeltaSpike BeanProvider class:getContextualReference(String) = Object

getContextualReference(Class) = T

getBeanDefinition(Class) = Set

getContextualReferences(Class) = List

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.

CamelContextAware

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.

Events

BeforeBeanDiscovery

AfterBeanDisovery

ProcessBean

ProcessInjectionTarget

ProcessObserverMethod

AfterDeploymentValidation

BeforeShutdown

Linking beans

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.

Demo application

Common problems

Problems ...

Domination of Spring style DI

Multiple contexts vs simplicity of extension

Magic done inside Camel

Configuring Camel Context bean

TODO

Support for discoveringIntercept Strategies

Event Notifiers

Executors

Resolvers

Transactional services without spring-tx

Any questions?

Thank you for coming!