May 24, 2015

Java EE 7 Bean scopes compared (part 1 of 2)



Having dissected the five standards of “Bean” definitions which are part of Java EE 7 in a previous blog post, I will in this article take a closer look at the various lifecycle “scopes” specified by these Bean definitions. Again, I created a simple demo web application which provides a comparison of JSF, CDI, EJB and “Dependency Injection for Java” Bean Scopes.

TL;DR? Jump into the demo immediately!

Java EE 7: More scopes, more confusion

Java EE 7 defines five notions of “JavaBeans” with partially overlapping, related or just plain incompatible definitions. I went more into the details in my blog post where I made a basic comparison of these five bean types. I judged the current situation as “modularity overkill” when looking at the bean types alone.

Things get even more confusing when looking at one of the most important properties of a Bean type – its lifecycle definition, as provided by its scope type. Three of the five aforementioned bean definitions come with their own scope definitions:
  • JSR-330: Dependency Injection for Java
  • JSR-346 (formerly JSR-299): Contexts and Dependency Injection for Java EE (CDI)
  • JSR-344 (formerly JSR-314): JavaServer Faces (JSF)
Also, the EJB specification distinguishes its individual bean types by their lifecycle properties, thus we can add this framework to the list for providing these “implicit scopes”:
  • JSR-345 (formerly JSR-318): Enterprise JavaBeans (EJB) Lite
…in total, there are 17 scopes available through bean class annotations! It is however important to know that one can use a scope for bean classes of its corresponding bean type only. In fact, the reasoning about which bean type to use in a certain situation is predominantly defined by the scoping requirements: First you decide which scope you need, then you decide the most suitable bean type which provides that scope.

This decision is not made easy as the scope definitions, very much like bean definitions, include ambiguity both in meaning and artifact naming, and clear walk-though documentation is apparently rare. I would assert that the latter is especially true to the latest addition of the “scopes family”: JSF’s flash scope and JSF’s / CDI’s flow scope.

Therefore, I created yet another JSF demo web application which compares the available bean scope definitions of Java EE 7 Web Profile. Feel free to download the source code, play with the live demo, or read on for more information and conclusions.

Exploring bean scope definitions: how the demo works

The demo web application I created is not based on JUnit tests; rather, it runs in the browser which allows you to interact with the server and observe page navigation consequences for the different bean scope definitions.

Within the demo application, for each scope definition under test, one bean class has been created and annotated appropriately. Their @PostConstruct / @PreDestroy methods are used to increase / decrease a counter on an @ApplicationScoped (global, infinite lifespan) bean (Counter) in order to observe the number of currently active beans, the number of previously created beans, and the number of previously destroyed beans of the given type. These numbers are then displayed in a comparison table on a JSF page.

Through eleven actions, the user can interact with the server and thus influence the lifecycle of the beans with immediate visual feedback to his actions:
  • GET to same page: Sends a GET request to the origin URL. This is as if the user refreshes the page in his browser or if he follows an <a> link to the same page.
  • GET with navigation: Sends a GET request to a different URL. This is as if the user navigates to a different URL, e.g. through an <a> link pointing to a different page.
  • POST to same page: Sends a POST request to the origin URL. This is like a <form>’s <h:commandButton> / <h:commandLink> submit action with void navigation outcome (a “postback”).
  • POST with navigation: Sends a POST request to the a different URL. This is like a <form>’s <h:commandButton> / <h:commandLink> submit action with String navigation outcome.
  • Begin CDI Conversation: Invokes the CDI @ConversionScoped bean’s Conversation#begin() method in order to start a conversation.
  • Forget CDI Conversation: Removes the cid HTTP request parameter which holds information about the current Conversation.
  • End CDI Conversation: Invokes the CDI @ConversionScoped bean’s Conversation#end() method in order to end a conversation.
  • Begin CDI Flow: Sets the navigation outcome to the id of a configured CDI flow in order to start a flow.
  • End CDI Flow: Sets the navigation outcome to the id of the return node of the current CDI flow in order to end the flow.
  • Invalidate session: Invokes ExternalContext#invalidateSession() in order to destroy the current session.
  • Reset: Resets the counter. Note that this will not reset the server’s state (as e.g. held in the session).
Additionally, the user may want to:
  • Destroy the session cookie on the client side: Remove the JSESSIONID cookie so the web application won’t recognize the user as being associated with a session already.
For this demo application, session timeout has been set to 5 minutes.

Some more “behind the scenes”

EJB's @MessageDriven

Omitted, because it doesn’t really represent a “scope”, but a special use case.

EJB's @Stateful

Because EJB @Stateful beans are not eligible for @Named to enable EL injection, I used a static helper method to retrieve the bean via CDI’s BeanManager.

Flash Scope

In order to keep track of the lifespan of objects put in flash scope in the same way as the application keeps track of beans in other scopes, I created an additional @RequestScoped JSF @ManagedBean,  but instead of referring to it directly in the EL, I pointed to a helper method which either retrieved the bean from the flash scope, or, if it is not present there, injects a new instance of the bean and puts it into flash scope (in JsfFlashLoader):
@ManagedProperty("#{flash}")
private Flash flash;

public JsfBeanRequestFlash loadBean() {
    JsfBeanRequestFlash instance = (JsfBeanRequestFlash) flash.get("jsfBeanFlash");
    if (instance == null) {
        instance = Faces.evaluateExpressionGet("#{jsfBeanRequestFlash}");
        flash.put("jsfBeanFlash", instance);
    }
    return instance;
}
At runtime, the application thus shows the expected behavior of switching between new bean creation and flash scoped bean retrieval.

Flow Scope

In order to use the same XHTML pages for flow scope tests which are used for all the other tests, I had to put them in the directory structure expected for flow pages.

The Flow is produced by a method in an @ApplicationScoped CDI bean (CdiFlowBuilder).

Run it!

This is an interactive demo application; its true value is perceived only if you go ahead and click yourself through it, playing with different actions and observing their consequences.

LIVE on WildFly

Click here to see a LIVE demo of the application running on WildFly 8.2.0 (hosted on OpenShift).

Note that for the live demo version, the Counter bean which takes track of the bean count has been switched from @ApplicationScoped to @SessionScoped so that each user gets his individual counter.

Watch on YouTube

If the live demo server is down and you don’t like installing the demo on your own server, you can here watch a simple click-through screen recording I uploaded to YouTube:

On your own server

Please feel free to download this demo application from GitHub and deploy it to your own server instance.

I encourage you to try out the demo application on your own, and draw your own conclusions before reading my own findings on the next page!


Pages: 1 2