• cdi
  • components
  • contexts
  • converters
  • el
  • eventlisteners
  • exceptionhandlers
  • facesviews
  • filters
  • functions
  • managedbeans
  • push
  • resourcehandlers
  • scripts
  • servlets
  • taghandlers
  • utils
  • validators
  • viewhandlers
 - 
  • ContextParam
  • Cookie
  • Eager
  • FacesConverter
  • FacesValidator
  • GraphicImageBean
  • Param
  • ViewScoped

Available since OmniFaces 1.8

The CDI annotation @Eager specifies that a scoped bean is to be eagerly instantiated.

JSF's own native managed beans are being deprecated in favor of CDI managed beans. One feature that those native JSF managed beans had that's not directly available for CDI managed beans is the ability to eagerly instantiate application scoped beans.

OmniFaces fills this void and even goes one step further by introducing the @Eager annotation that can be applied to @RequestScoped, @ViewScoped, @SessionScoped and @ApplicationScoped beans. This causes these beans to be instantiated automatically at the start of each such scope instead of on demand when a bean is first referenced.

In case of @RequestScoped and @ViewScoped beans instantiation happens per request URI / view and an extra attribute is required for specifying this.

Supported scopes

Currently supported scopes:

  1. CDI RequestScoped
  2. CDI ViewScoped
  3. OmniFaces ViewScoped
  4. CDI SessionScoped
  5. CDI ApplicationScoped

Usage

E.g. The following bean will be instantiated during application's startup:

@Eager
@ApplicationScoped
public class MyEagerApplicationScopedBean {

    @PostConstruct
    public void init() {
        System.out.println("Application scoped init!");
    }
}

Note: you can also use the stereotype @Startup for this instead.

The following bean will be instantiated whenever a session is created:

@Eager
@SessionScoped
public class MyEagerSessionScopedBean implements Serializable {

    private static final long serialVersionUID = 1L;

    @PostConstruct
    public void init() {
        System.out.println("Session scoped init!");
    }
}

The following bean will be instantiated whenever the URI /components/cache (relatively to the application root) is requested, i.e. when an app is deployed to /myapp at localhost this will correspond to a URL like http://localhost:8080/myapp/components/cache:

@Eager(requestURI = "/components/cache")
@RequestScoped
public class MyEagerRequestScopedBean {

    @PostConstruct
    public void init() {
        System.out.println("/components/cache requested");
    }
}

FacesContext in @PostConstruct

When using @Eager or @Eager(requestURI), be aware that the FacesContext is not available in the @PostConstruct. Reason is, the FacesServlet isn't invoked yet at the moment @Eager bean is constructed. Only in @Eager(viewId), the FacesContext is available in the @PostConstruct.

In case you need information from HttpServletRequest, HttpSession and/or ServletContext, then you can just @Inject it right away. Also, all other CDI managed beans are available the usual way via @Inject, as long as they do also not depend on FacesContext in their @PostConstruct.

Compatibility

In some (older) containers, most notably GlassFish 3, the CDI request scope is not available in a ServletRequestListener (this is actually not spec complicant, as CDI demands this scope to be active then, but it is what it is).

Additionally in some containers, most notably GlassFish 3 again, instantiating session scoped beans from a HttpSessionListener will corrupt "something" in the container. The instantiating of the beans will succeed, but if the session is later accessed an exception like the following will be thrown:

java.lang.IllegalArgumentException: Should never reach here
    at org.apache.catalina.connector.SessionTracker.track(SessionTracker.java:168)
    at org.apache.catalina.connector.Request.doGetSession(Request.java:2939)
    at org.apache.catalina.connector.Request.getSession(Request.java:2583)
    at org.apache.catalina.connector.RequestFacade.getSession(RequestFacade.java:920)
    at javax.servlet.http.HttpServletRequestWrapper.getSession(HttpServletRequestWrapper.java:259)
    at com.sun.faces.context.ExternalContextImpl.getSession(ExternalContextImpl.java:155)
    at javax.faces.context.ExternalContextWrapper.getSession(ExternalContextWrapper.java:396)
    at javax.faces.context.ExternalContextWrapper.getSession(ExternalContextWrapper.java:396)
    ...
If any or both of those problems occur, a filter needs to be installed instead in web.xml as follows:
<filter>
    <filter-name>eagerBeansFilter</filter-name>
    <filter-class>org.omnifaces.cdi.eager.EagerBeansFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>eagerBeansFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Note that the EagerBeansFilter will automatically disable the EagerBeansWebListener.

CDI issues in EAR

Note that CDI has known issues when OmniFaces is bundled in multiple WARs in a single EAR and the CDI feature is based on an Extension. It's important to understand that those issues are not related to OmniFaces, but to the broken CDI spec. For an overview of those issues, please refer Known issues of OmniFaces CDI features in combination with specific application servers.

Demo

Bean instantiated at beginning of request

A bean annotated with @Model (a stereotype for @RequestScoped and @Named) has been annotated with @Eager setting requestURI to the URI of this page relative to the application root. For the demo the @PostConstruct method will grab the current nano seconds time. When the bean is referenced on this page it will show the elapsed time in nanoseconds.

One usecase for this feature in a real application could be calling an @Asynchronous annotated method that loads data from a database and returns a Future. That way loading of this data and the processing of the request pipeline plus the building and rendering of a view up till the moment the Future#get() is referenced can overlap. A more concrete example can be found in the chapter Eagerly instantiate a CDI managed bean.

Elapsed time in nanoseconds since @Eager @RequestScoped bean initiated at the start of this request: 44495930 ns.
As comparison, elapsed time in nanoseconds since non-@Eager @RequestScoped bean initiated in this request: 84009 ns.
So, you have 44411921 ns time space to perform some @Asynchronous initialization.

Bean instantiated when application starts up

A bean has been annotated with @Startup (a stereotype for @Eager and @ApplicationScoped) and sets its startupDate property in the @PostConstruct method, which will thus represent the time this application started.

Application started at: 31 Jul 2017 13:23.00.611 UTC
As comparison, the JSF #{startup} is at: 31 Jul 2017 13:23.06.588 UTC
Demo source code
<h3>Bean instantiated at beginning of request</h3>
<p>
    A bean annotated with <code>@Model</code> <small>(a stereotype for @RequestScoped and @Named)</small> 
    has been annotated with <code>@Eager</code> setting <code>requestURI</code> to the URI of this page relative to the 
    application root.
    For the demo the <code>@PostConstruct</code> method will grab the current nano seconds time. When the bean is referenced
    on this page it will show the elapsed time in nanoseconds.
</p>
<p>
    One usecase for this feature in a real application could be calling an <code>@Asynchronous</code> annotated method that
    loads data from a database and returns a <code>Future</code>. That way loading of this data and the processing of the
    request pipeline plus the building and rendering of a view up till the moment the <code>Future#get()</code> is referenced 
    can overlap. A more concrete example can be found in the chapter
    <a href="http://balusc.omnifaces.org/2014/06/omnifaces-18-released.html" target="_blank">Eagerly instantiate a CDI managed bean</a>.
</p>

<blockquote>
    Elapsed time in nanoseconds since <code>@Eager @RequestScoped</code> bean initiated at the start of this request: <strong>#{myEagerRequestBean.elapsedTime} ns</strong>.
    <br/>
    As comparison, elapsed time in nanoseconds since non-<code>@Eager @RequestScoped</code> bean initiated in this request: <strong>#{myRequestBean.elapsedTime} ns</strong>.
    <br/>
    So, you have <strong>#{myEagerRequestBean.elapsedTime - myRequestBean.elapsedTime} ns</strong> time space to perform some <code>@Asynchronous</code> initialization.
</blockquote>

<h3>Bean instantiated when application starts up</h3>
<p>
    A bean has been annotated with <code>@Startup</code> <small>(a stereotype for @Eager and @ApplicationScoped)</small> and
    sets its startupDate property in the <code>@PostConstruct</code> method, which will thus represent the time this
    application started.            
</p>
<blockquote>
    Application started at: <strong>#{of:formatDateWithTimezone(myStartupBean.startupDate, 'd MMM yyyy HH:mm.ss.SSS', 'UTC')} UTC</strong>
    <br/>
    As comparison, the JSF <code>\#{startup}</code> is at: <strong>#{of:formatDateWithTimezone(startup, 'd MMM yyyy HH:mm.ss.SSS', 'UTC')} UTC</strong>
</blockquote>