Action based frameworks vs. Spring MVC; under the hood

This morning I was thinking about a question someone had asked me and things suddenly gelled in my head about the different ways that Stripes (and probably the other action based frameworks) and Spring MVC work.

In broad terms they both operate similarly; with Spring a URL is mapped to a Controller, with Stripes it’s mapped to an action bean. And each has a specific method to handle the requests, typically separate Java methods for the HTTP GET and POST requests. And both frameworks eventually hand off the displaying of the results response to a jsp page.

Because they’re quite similar in these broad terms, I’ve never clearly consciously understood their differences, until this morning.

What I finally realized is that the fundamental difference is that with Spring MVC, the Controller is a singleton and it’s shared by all of the HTTP requests that are going its URL. With Stripes, each time an HTTP request comes in it instantiates a new action bean to handle each request. Everything going on in that action bean is just for its own “private” HTTP request.

Thus, for example, with Spring MVC, you’d have a method like

@RequestMapping(method = RequestMethod.POST)
public String handlePostRequest(final ModelMap model) {

This is a method that’s been annotated to handle the HTTP POST request. (In Spring jargon you may see this method referred to as a handler method.) The important thing to note is its ModelMap parameter. A ModelMap is just a glorified HashMap; what you do with it is put in it the objects that you want displayed by the jsp page. Since it’s a parameter to the method, and that method is potentially being invoked by multiple threads (HTTP requests), each thread gets their own ModelMap instance.

The other kind of method you have with Spring MVC looks like this

@ModelAttribute("states")
public List<State> getStates() {

This is another way that data is given to the jsp view page. Because the Controller is a singleton, and it’s shared by all of the threads and requests going to its url, this method is also shared. Therefore, what it returns is anything that will be the same for all of the HTTP requests coming to this Controller. For example, if this Controller is processing a form for a place of birth, this could be returning all of the States in the US. In Spring jargon this is called reference data.

Let’s compare this with Stripes. With Stripes you also have getter methods, which appear to be called by the jsp to fill in ${actionBean.whatever} references. But the Stripes action bean was instantiated for just that HTTP request, so its getter methods can return data that’s specific to that particular HTTP request, or data that’s suitable for all requests. It’s quite nice when you stop and think about it, because you don’t need to use two different ways of returning data to the jsp view; on the one hand adding data to the ModelMap in the handler method, and on the other, returning data from a @ModelAttribute annotated method.

Here’s another thing that’s nice about Stripes. If you have multiple properties on some data that the jsp is displaying, for example

${actionBean.person.name}
${actionBean.person.gender}
${actionBean.person.dateOfBirth}

The jsp will, in this example, make 3 calls (at least) to the getPerson() method. If you’re fetching the Person from a database, it could be making a database call each time. With Stripes, the getter looks like this

public Person getPerson() {
    return (this.person);
}

Where person is a class field; a class instance variable. It’s set in the request handler method, which is called once, for the HTTP request. For example, my request handler method calls a local helper method, prepareView(), which contains

protected void prepareView() {
    this.person = this.personService.findByName("John Doe");
}

On the flip side, for incoming data, GET parameters or POST data, with Stripes all you need are setter methods. The parameters or POST data are properties on the action bean and Stripes sets them for you.

With Spring MVC and incoming data, it’s definitely not a pretty picture

@RequestMapping(method = RequestMethod.POST)
public String handlePostRequest(final ModelMap model,
        @ModelAttribute("hostsForm") final HostsForm hostsForm,
        final Errors errors,
        final SessionStatus status) {

Here, the @ModelAttribute is annotating one of the method’s parameters, the incoming POST data in this case. What’s really disturbing is that they use the same annotation, @ModelAttribute, for two different things; incoming data and outgoing data.

I think that the main thing I’ve learned from this is that when you instantiate an object for each HTTP request, it gives you a lot more flexibility compared to having a singleton bean.

Advertisements


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s