- 

Available since OmniFaces 1.8

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

Faces native managed beans have been deprecated in favor of CDI managed beans. One feature that those Faces native 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 https://example.com/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.

CDI issues in EAR

Note that CDI has known issues when the same web fragment library 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 CDI spec. For an overview of those issues, please refer Known issues of OmniFaces CDI features in combination with specific application servers. Needless to say is that EAR is a dead end since introduction of the cloud and has no value in the microservices world. In other words, if you want to use CDI (or microservices), then you shouldn't be using an EAR in first place.

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: 13805786 ns.
As comparison, elapsed time in nanoseconds since non-@Eager @RequestScoped bean initiated in this request: 22372 ns.
So, you have 13783414 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: 16 Sep 2024 11:13.01.380 UTC
As comparison, the Faces #{startup} is at: 16 Sep 2024 11:13.01.379 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="https://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 Faces <code>\#{startup}</code> is at: <strong>#{of:formatDateWithTimezone(startup, 'd MMM yyyy HH:mm.ss.SSS', 'UTC')} UTC</strong>
</blockquote>