The Spring Framework
is a popular application framework for Enterprise Java applications,
featuring a powerful Dependency Injection mechanism
(also known as Inversion of Control) for creating and
configuring "plain old Java objects" (POJOs) on the fly. Since
verson 1.1.5, Spring has included an expression evaluation
mechanism (see below) for integration with JavaServer
Faces. Shale adds the ability to programmatically access the Spring
WebApplicationContext
for the current application.
Spring provides a custom JavaServer Faces
VariableResolver
implementation that extends the standard
JavaServer Faces managed beans mechanism. When asked to resolve a
variable name, the following algorithm is performed:
WebApplicationContext
for this
application? If so, use it to create and configure an instance,
and return that instance to the caller.null
instead.Separately, Shale also provides a custom
VariableResolver
that exposes Spring's
WebApplicationContext
instance for the current
application, using variable name webApplicationContext
to look it up. This is useful when an event handler wishes to
explicitly invoke the bean factory to create beans on demand,
such as a bean that encapsulates the business logic to be performed
when a submit button is pressed.
In order to utilize the Spring integration, you will need to include
Spring in your web application. You can either include the all-in-one
version (spring.jar
) or the necessary individual
components (spring-core.jar
,
spring-context.jar
, and spring-web.jar
).
In order to utilize the Shale feature that exposes the
webApplicationContext
instance, you will need to
include shale-spring.jar
.
Here are some sample use cases for leveraging the integration capabilities:
Imagine you have an application scope bean that contains domains (the lists of selection items used in drop down components) for your application. You might bind a component to a property of this bean as follows:
<h:selectOneMenu id="category" value="..." ...> <f:selectItems value="#{domains.categories}"/> </h:selectOneMenu>
where the underlying object referenced by the logical name
domains
is expected to have a getCategories()
method with a return type of SelectItem[]
.
The underlying bean class might be defined as a managed bean
in /WEB-INF/faces-context.xml
:
<managed-bean> <managed-bean-name>domains</managed-bean-name> <managed-bean-class> com.mycompany.mypackage.MyDomainsImpl </managed-bean-class> <managed-bean-scope>application</managed-bean-scope> ... configuration of managed properties ... </managed-bean>
or as a Spring bean in /WEB-INF/applicationContext.xml
:
<bean id="domains" class="com.mycompany.mypackage.MyDomainsImpl" singleton="true"> ... configuration of managed properties ... </bean>
The binding expression will work with either definition of the bean, transparently.
Assume you have business logic to manage updating a customer
database in a bean with logical name CustomerDAO
.
In the event handler for a submit button (here, assuming that
your backing bean extends AbstractViewController
or
AbstractFacesBean
), you can acquire a reference to
the appropriate instance of this business logic bean by
using a value binding expression programmatically:
CustomerDAO dao = (CustomerDAO) getValue("#{CustomerDAO}");
Again, the logic utilizing this expression is agnostic to whether the bean is actually created by JSF's managed bean facility, or by Spring's bean factory.
In some circumstances, applications will want to explicitly
interact with Spring's bean factory (in a web application, this
is typically an instance of WebApplicationContext
.
In order to retrieve the application wide instance of this
class for the current web application, you may evaluate a
value binding expression with a particular reserved name:
WebApplicationContext wac = (WebApplicationContext) getValue("#{webApplicationContext}");
Once you have this reference, you can explicitly invoke its methods to create or manage bean instances. Interacting with it, of course, is using Spring facilities directly, so you are no longer able to transparently use managed beans. However, you do have direct access to the extra facilities provided by Spring.