Mastering JavaServer Faces 2.2
上QQ阅读APP看书,第一时间看更新

Beans injection

Normally, solutions depend on the concrete functional requirements, but finding the right solutions is what makes the difference between developers. Sometimes, developers get stuck or make mistakes when they work with objects in a scope that uses objects from another scope. From the following figure, you can seek some guidance for dealing with some of the most popular cases:

Note

As you can see, there are some restrictions. As a general rule in JSF, don't use objects that have shorter lifespan than the objects you are calling it from. In other words, use objects whose lifespan is the same as, or longer than, the object being injected into. Breaking this rule will end up in a JSF exception.

The logic behind this rule can be explained through the two most common mistakes, which are as follows:

  • Use request objects in session objects: This is a bad thing, because we will have lots of requests (lots of instances) and only one session (one instance). Usually, requests belong to all users, while a session is one per user; therefore, it is unclear request object is injected? To be more clear, lots of requests means lots of associated beans, while a session means one bean. Now, it is illogical to inject one particular instance and skip all others. Moreover, how and when will you fetch the correct instance, since the request objects are transient, and usually, have a short lifespan! Even if you find a plausible use case, JSF will not allow you to do this via JSF managed beans.
  • Use session objects in application objects: The same logic can be applied further when we want to use session objects in application objects. Sessions are many as users, but the application is only one; therefore, you cannot inject all sessions in the application ... it is useless! Of course, you may want to fetch a certain session to the application, but you have to be sure that the pointed session exists; this is not a problem if you are interested in the session of the current user, but it may be an issue if you are interested in sessions of other users. Moreover, if there are many sessions, you have to correctly identify the desired session. Even if you find a plausible use case, JSF will not allow you to do this via JSF managed beans.

Nevertheless, for CDI, these cases are not such a big issue. When you are using an object that has a shorter lifespan than the object you are calling it from (for example, injecting a request scoped bean into a session scoped bean), CDI classifies the use case as a mismatched injection and fixes the issue via CDI proxies. For each request, the CDI proxy re-establishes the connection to a live instance of the request scoped bean.

Even when we follow the written rules, we are still vulnerable to the unwritten rules. One of the unwritten rules that can cause undesirable results is named overuse or abuse. The following are some cases to avoid:

  • Overusing a view scoped bean for request scoped data may affect memory.
  • Overusing a request scoped bean for view scoped data may cause forms with unexpected behavior.
  • Overusing an application scoped bean for request/view/session scoped data may cause an undesirably wide visibility of data across users and will affect memory.
  • Overusing a session scoped bean for request/view data may cause an undesirably wide visibility of data across multiple browser windows/tabs in that session. As you know, view data are specific to a single browser window/tab, which allows us to open multiple tabs and keeps the data integrity while switching between tabs. On the other hand, if this data was exposed via the session scope, then the modifications in one window/tab will be reflected in the browser session; therefore, switching between tabs will lead to an apparently strange behavior, known as inconsistency of data. In case of using the session scope for request/view data, will also affect memory, since request/view scopes are meant to have a shorter lifespan than session scope.

Starting with JSF 2.0, managed beans can be injected (dependency injection) into the property of another managed bean using the @ManagedProperty annotation. You already know that from the previous chapter, where an example is provided.

Another way to inject beans is to use the @Inject annotation, which is part of the CDI powerful injection mechanism.

So when do we use @ManagedProperty and when do we use @Inject ? Well, we know that both of them do the same thing in different ways and different containers, so maybe it is a good idea to use @ManagedProperty when you are working in a servlet container or just don't need CDI. Another good argument for @ManagedProperty is that you can use EL with it. But, if you are in a proper CDI environment where you can exploit CDI benefits, such as proxy scope leak prevention or better deploy-time dependency, then use CDI.

The pacifist approach will combine these two in the same application. In this case, you have two options: to avoid any interaction between the managed beans and CDI beans or, obviously, to encourage the interaction between them for better performance. If you choose the second option, then it is important to keep in mind some simple rules of injection as shown in the following figure: