Dashboard > Development > Development > Spring
Spring Log In View a printable version of the current page.

Added by Herko ter Horst , last edited by Herko ter Horst on 2008-11-17  (view change)
Labels: 
(None)

Intended to discuss the way we use Spring in our projects.

Spring basics

At its very core, Spring is only two things:

  • Inversion of Control (IoC)
  • JavaBeans

IoC means your classes don't have to take care of their own external dependencies. Instead, they wait for some external component to set those dependencies on them (either using a constructor or a setter method).

The use of JavaBeans means you don't have to implement any Spring interfaces, directly use any Spring classes or even be aware that you're using Spring as long as you adhere to the JavaBeans standard (mostly this just means having getXxx() and setXxx() methods for a field called xxx that you want to have managed by the IoC container).

Bean scopes

Beans in a Spring application context can be scoped for different usage scenarios. Most beans will have the singleton scope, meaning only one instance of that bean will be created during the lifetime of the application. The other core Spring scope is the "prototype" scope, which means an instance of that bean is created every time it is referenced by another bean in the configuration. There are a few more scopes that are specific to web applications: request, session and global session. These are explained later.

The XML configuration

This is where the Spring "magic" happens. Instead of hard-coding dependencies between objects, Spring uses a configuration file to create connections between (named) beans. The Spring framework takes care of instantiating the objects in the right order and calling the appropriate getters and setters to make sure each object gets what it needs.

The concept is similar to a main method that does all this. For example, the following Spring configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

    <bean id="adunaAppVersion" class="info.aduna.app.AppVersion">
    	<property name="major" value="1" />
    	<property name="minor" value="0" />
    	<property name="modifier" value="SNAPSHOT" />
    </bean>
    
    <bean id="adunaAppConfig" class="info.aduna.app.AppConfiguration" init-method="init" destroy-method="destroy">
    	<property name="applicationId" value="my-app" />
    	<property name="version" ref="adunaAppVersion" />
    </bean>

    <bean id="myApplication" class="com.example.MyApplication" init-method="start">
        <property name="version" ref="adunaAppVersion" />
        <property name="config" ref="adunaAppConfig" />
    </bean>
</beans>
is pretty much equivalent to this Java code:

package com.example;

import info.aduna.app.*;

public class MyMain {
  public static void main(String[] args) {
    AppVersion version = new AppVersion();
    version.setMajor(1);
    version.setMinor(0);
    version.setModifier("SNAPSHOT");

    AppConfiguration config = new AppConfiguration();
    config.setApplicationId("my-app");
    config.setVersion(version);

    MyApplicaton myApplication = new MyApplication();
    myApplication.setVersion(version);
    myApplication.setConfig(config);

    myApplication.start();
  }
}

The advantage of using the XML configuration is that you decouple the creation of the objects from the application, allowing you to easily replace one object with another. MyMain would need extensive refactoring for it to accept another AppConfiguration implementation, for example.

Spring Web MVC

We currently apply Spring mostly in our web application projects. In addition to the core Spring functionality of wiring beans together, we also make use of specific functionality from the Spring Web MVC project. This means we use "Spring Web MVC"-specific classes and interfaces to make our life easier.

Spring Web MVC helps create web applications based on the Model-View-Controller design pattern. It provides ways to connect (HTTP) requests to model, view and controller instances through the use of (request)mappings and (view-)resolvers. It also provides functionality similar to a servlet filter through the use of interceptors. Note that while the Controllers and Views are Spring Web MVC-specific, the models are NOT. The models (usually represented as a Map) contain instances of domain-specific classes that have no knowledge of Spring or Spring Web MVC.

The central concept in Spring Web MVC is the Controller. The most basic Controller interface features just on method:

public interface Controller {

    /**
     * Process the request and return a ModelAndView object which the DispatcherServlet
     * will render.
     */
    ModelAndView handleRequest(
        HttpServletRequest request,
        HttpServletResponse response) throws Exception;

}
Spring Web MVC provides several implementations of this interface that provide support for common use cases within a web application, such as displaying, validating and processing a form. Spring Web Flow (which we currently don't use) provides even more advanced support for complex interactions across multiple pages.

Request to Controller

Incoming HTTP requests are connected to a Controller instance by way of HandlerMappings. We commonly use the org.springframework.web.servlet.handler.SimpleUrlHandlerMapping which selects a Controller based on the request URL. For example, this configuration fragment selects the ProtocolController when the incoming request URL ends with "/procotol":

<bean id="openrdfProtocolUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
  <property name="order" value="0" />
  <property name="alwaysUseFullPath" value="true"/>		
  <property name="mappings">
    <props>
      <prop key="/protocol">openrdfProtocolController</prop>
    </props>
  </property>
</bean>

<bean id="openrdfProtocolController" class="org.openrdf.http.server.protocol.ProtocolController" />

View name to actual View

A Controller returns a ModelAndView object that contains either the "name" of a view or a full-fledged View object. In the latter case, the View object will have to take care of rendering the view itself. However, when the result a view name, a Resolver is used to select the actual view. In our web apps, we mostly rely on a resolver provided by Spring to transform view names into views rendered from JSP/JSTL files:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
  <property name="prefix" value="/WEB-INF/views/" />
  <property name="suffix" value=".jsp" />
</bean>
This basically takes the view name, prefixes it with /WEB-INF/views/, tacks on .jsp at end and then renders that JSP file using the JstlView class.

Additional bean scopes and the AOP proxy.

Specifically for use in web applications, Spring defines three additional bean scopes in addition to the singleton and prototype scopes: request, session and global session (the latter is mostly used for portal environments). For these to work, a proxy object is needed in order to resolve the bean dependency when, for example, a Controller bean is created. The proxy will take care of instantiating the actual object when it is needed (one for each HTTP request, or one for each HTTP session). The official documentation explains how this works.

Annotation-based configuration

We don't use this yet, but as of Spring 2.5 it is possible to move a lot (if not all) of the configuration from the XML file into Java, using annotations. I wouldn't recommend doing this for all of our code as it does create a dependency on Spring in those classes. However, I think it would be appropriate to use this for the Spring Web MVC classes, as A) they already depend on Spring anyway; and B) using annotations there makes the most sensel, especially for those annotations that deal with things like: which HTTP methods does this controller accept; or obtaining and transforming request parameters.

Powered by a free Atlassian Confluence Open Source Project License granted to Aduna Open Source. Evaluate Confluence today.
Powered by Atlassian Confluence 2.7, the Enterprise Wiki. Bug/feature request - Atlassian news - Contact administrators