Injecting Spring-managed beans - Java-Springs

Assume we have the following simple Spring container definition

Inside the Tapestry application, the above bean definitions need to be loaded into a Spring container, and any relevant Tapestry pages need to be supplied (injected) with the authenticationService and userService beans, which implement the Authentication Service and UserService interfaces, respectively.

At this point, the application context is available to a web application by calling Spring's static utility function Web Application Context Utils. get Application Context (servlet Context), where servletContext is the standard Servlet Context from the Java EE Servlet specification. As such, one simple mechanism for a page to get an instance of the User Service, for example, would be with code such as:

This mechanism does work. Having said that, it can be made a lot less verbose by encapsulating most of the functionality in a method in the base class for the page or component. However, in some respects it goes against the IoC principle; ideally you would like the page to not have to ask the context for a specific bean by name, and in fact, the page would ideally not know about the context at all.

Luckily, there is a mechanism to allow this. We rely upon the fact that Tapestry already has a mechanism to declaratively add properties to a page, and it is in fact the preferred approach to manage all properties on a page in this declarative fashion, so that Tapestry can properly manage their lifecycle as part of the page and component lifecycle.

Dependency Injecting Spring Beans into Tapestry pages

First we need to make the ApplicationContext available to the Tapestry page or Component without having to have the ServletContext; this is because at the stage in the page's/component's lifecycle when we need to access the ApplicationContext, the ServletContext won't be easily available to the page, so we can't use Web ApplicationContextUtils.getApplicationContext(servletContext) directly. One way is by defining a custom version of the Tapestry IEngine which exposes this for us:

This engine class places the Spring Application Context as an attribute called "appContext" in this Tapestry app's 'Global' object. Make sure to register the fact that this special IEngine instance should be used for this Tapestry application, with an entry in the Tapestry application definition file.

For example:

file: xportal.application:

Component definition files

Now in our page or component definition file (*.page or *.jwc), we simply add property-specification elements to grab the beans we need out of the Application Context, and create page or component properties for them. For example:

The OGNL expression inside the property-specification specifies the initial value for the property, as a bean obtained from the context. The entire page definition might look like this:

Adding abstract accessors

Now in the Java class definition for the page or component itself, all we need to do is add an abstract getter method for the properties we have defined (in order to be able to access the properties).

For the sake of completeness, the entire Java class,

for a login page in this example, might look like this:

package com.whatever.web.xportal.pages;

/**

* Allows the user to login, by providing username and password.

* After successfully logging in, a cookie is placed on the client browser

* that provides the default username for future logins (the cookie

* persists for a week).

*/

Dependency Injecting Spring Beans into Tapestry pages - Tapestry 4.x style

Effecting the dependency injection of Spring-managed beans into Tapestry pages in Tapestry version 4.x is so much simpler. All that is needed is a single add-on library, and some (small) amount of (essentially boilerplate) configuration. Simply package and deploy this library with the (any of the) other libraries required by your web application (typically in WEB-INF/lib).

You will then need to create and expose the Spring container. You can then inject Spring-managed beans into Tapestry very easily; if we are using Java 5, consider the Login page from above: we simply need to annotate the appropriate getter methods in order to dependency inject the Spring-managed userService and authenticationService objects (lots of the class definition has been elided for clarity).

We are almost done. All that remains is the HiveMind configuration that exposes the Spring container stored in the ServletContext as a HiveMind service; for example:

If you are using Java 5 (and thus have access to annotations), then that really is it.

If you are not using Java 5, then one obviously doesn't annotate one's Tapestry page classes with annotations; instead, one simply uses good old fashioned XML to declare the dependency injection; for example, inside the .page or .jwc file for the Login page (or component):

In this example, we've managed to allow service beans defined in a Spring container to be provided to the Tapestry page in a declarative fashion. The page class does not know where the service implementations are coming from, and in fact it is easy to slip in another implementation, for example, during testing. This inversion of control is one of the prime goals and benefits of the Spring Framework, and we have managed to extend it throughout the stack in this Tapestry application.


All rights reserved © 2018 Wisdom IT Services India Pvt. Ltd DMCA.com Protection Status

Java-Springs Topics