Skip navigation
2013
mkouba

Bean archives in CDI 1.1

Posted by mkouba Sep 20, 2013

Unlike CDI 1.0, the CDI 1.1 specification defines two types of bean archives: explicit and implicit. The first one is de facto the good old CDI 1.0 bean archive where all types in the archive are considered, i.e. the type metadata are inspected, the container must determine whether it is a bean, validate it, etc. If you place an empty beans.xml or CDI 1.0-specific  beans.xml you'll end up with an explicit bean archive. If you want to follow the new XSD for CDI 1.1, the bean discovery mode must be set to all:

 

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.1" bean-discovery-mode="all">
</beans>








 

The other type - implicit bean archive - is much more interesting and to be honest it also brings one compatibility issue. First let's look at the differences. The specification clearly states that an implicit archive contains one or more bean classes with a bean defining annotation, or one or more session beans. So that it doesn't have to contain a beans.xml file. However it may contain a  beans.xml file with the bean-discovery-mode of annotated.

 

For implicit bean archive the container only inspects Java classes annotated with a bean defining annotation during bean discovery. Bean defining annotation is any scope type (e.g. @RequestScoped, @Dependent). So this is more like good old Seam2 where a component must be explicitly designated. I think this is the real benefit of implicit bean archives in CDI 1.1 - disable automatic inspection of all types present in the archive without the need of exclude filters defined in beans.xml (exlude filters are now part of the spec, previously a special feature of Weld).

 

And now the issue. CDI is built on top of JSR 330 and makes use of its annotations (@Inject, @Qualifier, ...). Unfortunately javax.inject.Scope identifies pseudo-scopes in CDI. And so any archive (even not intended to be a CDI bean archive) which contains a class annotated with any scope annotation becomes an implicit bean archive, i.e. beans are discovered, validated, etc. This might cause problems with archives which use any other injection framework based on JSR 330 (e.g. very useful Guava - Issue 1433).

 

One solution is to use beans.xml with the bean-discovery-mode of "none" - this tells the container to skip the archive. However this also breaks backwards compatibility, because such an archive will be recognized in CDI 1.0.

 

The CDI 1.1 also states:

"For compatibility with Contexts and Dependency 1.0, products must contain an option to cause an archive to be ignored by the container when no beans.xml is present."

It seems this is the only way to handle this issue correctly. On the other hand it makes your application non-portable. If you have any idea how to fix it post a comment to CDI-377.

 

UPDATE: A colleague of mine (thanks Jozef!) pointed out that there is one more possibility - according to the spec an archive which contains a CDI extension and no beans.xml file is not a bean archive either. But of course this is rather a hack solution for our problem.

 

See also the CDI 1.1 specification, section 12.1. Bean archives and 12.4. Bean discovery.

This is a new feature introduced in Weld 2.1.0.Beta2 (see also WELD-1480 and WELD-1501). It's not portable (i.e. will not work with other CDI implementations) but might be useful.

 

According to the CDI specification some built-in contexts (request, session and conversation) must be always active during the service() method of any servlet in the web application. This means context activation and deactivation per every HTTP request and also handling conversation stuff (e.g. associating long running conversation with the request) in the case of conversation context. For some scenarios this represents unnecessary overhead. The first scenario example that comes to my mind is serving resources (CSS, JavaScript, images, audio, etc.). But it may also apply to legacy components which do not make use of CDI services.

 

Weld allows to define a special activation filter component - HttpContextActivationFilter - so that only matching HTTP requests result in context activation/deactivation. Basically there are two ways to enable/configure this component. First the integrator (e.g. WildFly application server) is allowed to provide an implementation and utilize its own configuration mechanism. Secondly - if the integrator doesn't support this option - a special initialization parameter may be associated with a web application to activate a built-in regular expression-based activation filter.

 

E.g. to match paths with suffix ".html" and ".xhtml" place the following init param in your web.xml:

    <context-param>
        <param-name>org.jboss.weld.context.mapping</param-name>
        <param-value>(.*\.html|.*\.xhtml)</param-value>
    </context-param>






 

Param value is a regular expression and is matched againts the request URI without the context path, i.e. /foo for http://localhost:8080/myapp/foo?action=test (try Visual Regex Tester from ocpsoft.org to test your mappings if not sure :-). Note that Weld only supports one activation filter at a time and integrator has always precedence. You should see a warning log if your web.xml mapping definition is ignored.

 

My quick and dirty tests showed up that using built-in regular expression-based activation filter can save several milliseconds* for each request which does not require CDI services. It's not that much but it counts!

 

* Resource consumption was not monitored.

Filter Blog

By date:
By tag: