Monday, April 22, 2013

one container everywhere

based on the title you might think that this post is about spring. but it's about cdi with some references to spring/guice/... . however, it is not about spring vs cdi. it's just about wrong myths about cdi (compared to other containers like spring-core/guice/...)

esp. spring and cdi are so close that you can do almost everything with cdi what you can do with spring and the other way round. your project won't fail because you used one of it instead of the other one. if you have spring(-core) know-how already, it will take you about 2-3 days to know the same about cdi and the other way round. however, if you are in favour of the spring-framework, a lot of config options, one vendor,... , you should go with it. once you have the right dependency- and config-setup, the productivity with spring will be similar as long as you are aware of some topics like explicit proxy-configs in case of injection of beans with a narrow scope into beans with a wider scope. (that shouldn't be an offence - for sure also cdi has its pitfalls.)

let's have a look at some myths:

myth #1

with spring/guice/... everything is more flexible, since you just need to replace some jar-files for using a new version.

the same integration points to run spring/guice/... in your application-server are also available for a custom version of cdi (added in WEB-INF/lib).

myth #2

you can't upgrade the cdi container in your ee6 server.

technically you can do it. i did it already with tomee, glassfish3 and as7. the main question here is, if you are allowed to do it and/or you have the needed access to do it.

myth #3

once you picked an ee6 server, you have to use what you have in there.

a lot of specifications and/or the server itself allow/s to use other implementations. however, in case of cdi the container is integrated very deeply. using an other cdi implementation has the same restrictions as you will face with spring/guice/... . so you can do it, but not with keeping the full (cross-)integration like injecting cdi beans in ejbs. however, you can still use the cdi container to do a (bean-)lookup manually (as you would do with spring/guice/...). (preview: cdi 1.1 offers new SPIs which enable servers to provide even more out-of-the-box.)

myth #4

you can't use owb in an ee6 server which ships weld per default.

as mentioned in myth #3 you can do it with the same restrictions you would face with spring/guice/... concerning (cross-)integration. the following part is tested with glassfish (for as7 you would need a custom WebScannerService which supports the jboss vfs). there are different approaches:

approach 1:
in some cases it's enough just to add owb in WEB-INF/lib. e.g. in combination with jsf the el-resolver of owb will be called before the internal el-resolvers (like it is with spring/guice/...). however, you might face issues with some more restrictive checks done by weld (e.g. bda-rules). -> continue with:

approach 2:
exclude all packages via the scan-tag of the namespace (in beans.xml) -> only owb will find your beans.
owb is very pluggable. with a custom WebScannerService you can just use a different file-name for the marker file (e.g. owb_beans.xml instead of beans.xml). you just have to copy the default implementation, replace some strings and enable it in that means weld won't find your beans, but owb will find them (or the other way round for servers which ship owb per default). however, you might have implementations of javax.enterprise.inject.spi.Extension. -> continue with:

approach 3:
this approach can be combined with approach 2. you can veto beans for weld. just inject the bean-manager in your ProcessAnnotatedType observer and veto the bean if the bean-manager class is from weld:

however, you might use a cdi-extension like codi or deltaspike and there it isn't enough to rename the marker-files or filter beans, because e.g. BeanManagerProvider will find the BeanManager of weld or of owb. since there is no rule (if both are in the classpath), the behaviour would be random. so you have to patch such cdi-extensions. e.g.:

myth #5

cdi is hard(er) to use, because you don't get a reference to the container.

that's an easy task with owb as well as with weld. you can do it on your own or just use the CDI-Ctrl module provided by DeltaSpike. (with cdi 1.1 it will be possible out-of-the-box.)