Spring Framework

Feature Summary

Inversion of Control (IoC)

http://martinfowler.com/articles/injection.html

The Spring IoC container is implemented through the BeanFactory interface or through it's superset interface, ApplicationContext.

Dependency Injection

Dependencies are also known as collaborators.

The Spring team advocates using setter injection in preference to constructor injection, however it is by no means mandated.

Constructor Injection

<bean id="example1" class="examples.Example1">
    <constructor-arg index="0"><ref bean="otherBeanRef"/></constructor-arg>
    <constructor-arg index="1" ref="anotherBeanRef"/>
</bean>

public class Example1 {
    private OtherBean otherBean;
    private AnotherBean anotherBean;
    public Example1(OtherBean ob, AnotherBean ab) {
        this.otherBean = ob;
        this.anotherBean = ab;
    }
}

The 'index' attribute is only needed where the arguments cannot be clearly distinguished based on their type. They are actually unnecessary in the above example.

Static factory method

<bean id="example1" class="examples.ExampleFactory"
        factory-method="createInstance">
    <constructor-arg><ref bean="otherBeanRef"/></constructor-arg>
    <constructor-arg ref="anotherBeanRef"/>
</bean>

public class Example1 {
    private OtherBean otherBean;
    private AnotherBean anotherBean;
    private Example1(OtherBean ob, AnotherBean ab) {
        this.otherBean = ob;
        this.anotherBean = ab;
    }
    public static Example1 createInstance(OtherBean ob, AnotherBean ab) {
           return new Example1(ob, ab);
    }
}

Setter Injection

<bean id="example2" class="examples.Example2">
    <property name="otherBean" ref="otherBeanRef"/>
    <property name="anotherBean"><ref bean="anotherBeanRef"/></property>
</bean>

public class Example2 {
    private OtherBean otherBean;
    private AnotherBean anotherBean;
    public void setOtherBean(OtherBean ob) {
        this.otherBean = ob;
    }
    public void setAnotherBean(AnotherBean ab) {
        this.anotherBean = ab;
    }
}

Using idref

If you use the ref attribute or element to reference another bean, the reference can be by either the other bean's id or name elements. If you use the idref element instead, the id is used and Spring validates that it exists.

Additionally, be using the idref element's local attribute, the validation occurs when the XML document is first parsed. The target id must exist within the same file.

<bean id="example2" class="examples.Example2">
    <property name="otherBean"><idref bean="otherBeanRef"/></property>
    <property name="anotherBean"><idref local="anotherBeanRef"/></property>
</bean>

Injecting Values

<bean id="example3" class="examples.Example3">
    <property name="stringValue1" value="abc"/>
    <property name="stringValue2"><value>def</value></property>
    <property name="intValue" value="123"/>
</bean>

Collections

<bean id="example4" class="examples.Example4">
    <property name="properties">
        <props>
            <prop key="com.fdsd.co.uk.value1">abc</prop>
            <prop key="com.fdsd.co.uk.value2">123</prop>
        </props>
    </property>
    <property name="myProperties">
        <value>
          com.mydomain.value1=abc
          com.mydomain.value2=123
        </value>
    </property>
    <property>
        <list>
            <value>a value</value>
            <ref bean="example3"/>
        </list>
    </property>
    <property>
        <map>
            <entry>
                <key><value>com.fdsd.co.uk.value1</value></key>
                <value>abc</value>
            </entry>
            <entry key="com.fdsd.co.uk.value2" value="123"/>
            <entry key-ref="example3" value-ref="a value"/>
        </map>
    </property>
    <property>
        <set>
            <value>a value</value>
            <ref bean="example3"/>
        </set>
    </property>
</bean>

Specifying a null Value

<bean class="examples.Example5">
    <property name="example"><null/></property>
</bean>

Using p-namespace to Specify Properties

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/>

    <bean name="example6"
        class="examples.Example6"
        p:givenName="John"
        p:surname="Smith"
        p:example-ref="example5"
    />

</beans>

Compound Property Names

Where Example7 has a foo property which in turn has a bar property:

<bean class="examples.Example7">
    <property name="foo.bar" value="abc"/>
</bean>

Autowiring

Mode Explanation

no No autowiring. The default. Must use ref element

byName Autowire by property name. The property must have exactly the same name as the bean to be wired

byType Autowire by type where there is only one bean of that type in the container

constructor Same as byType for constructor arguments

autodetect Chooses constructor or byType through introspection. If a default constructor is found, the byType mode is used

Table: Autowiring Modes

Dependency Checking

<bean class="examples.Example8" dependency-check="none"/>

Mode Explanation

none No dependency checking

simple Check primitive types and collections, not collaborators

object Check collaborators only

all Check both primitive types, collections and collaborators

Table: Dependency Checking Modes

Method Injection

Method injection is needed in situations where a singleton scoped bean requires a new prototype bean to be instantiated on each call to a particular methodon the singleton bean. There are a number of solutions described in the Spring Reference Documentation.

Scopes

  • singleton
  • prototype
  • request - scoped to lifecyle of single HTTP request
  • session - scoped to lifecycle of single HTTP session
  • global session - scoped to lifecycle of a global HTTP session, typically, a portlet context

Prototype Scoped Bean

Clean up is the responsibility of the client code.

Initial Web Configuration

Configuration to enable request, session and global session scoping is only required if you are not using Spring MVC.

Servlet 2.4

Add a listener to web.xml

<web-app>
  ...
  <listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
  </listener>
  ...
</web-app>

Servlet 2.3

Add a filter to web.xml

<web-app>
  ..
  <filter>
     <filter-name>requestContextFilter</filter-name>
     <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
  </filter>
  <filter-mapping>
     <filter-name>requestContextFilter</filter-name>
     <url-pattern>/*</url-pattern>
  </filter-mapping>
  ...
</web-app>

Scoped Beans as Dependencies

The scoped bean must be wrapped by a proxy that will obtain the correct instance of the scoped (request, session or global session) bean.

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

    <bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
           <aop:scoped-proxy/>
    </bean>

    <bean id="options" class="com.foo.Options" scope="session">
           <aop:scoped-proxy proxy-target-class="false"/>
    </bean>

    <bean id="userService" class="com.foo.SimpleUserService">
         <property name="userPreferences" ref="userPreferences"/>
    </bean>

</beans>

The first form of uses the CGLIB library to create the proxy. The second form uses standard JDK interface-based proxies, which requires the bean to implement an interface which all collaborators reference.

Beans

TODO:: Insert table "The bean definition" from spring-reference page 31, section 3.2.3 "The beans"

Element xxx

class

name

scope

constructor arguments

properties

autowiring mode

dependency checking mode

lazy-initialization mode

initialization method

destruction method

Table: The bean definition

Instantiating Beans

Beans can be instantiated by one of the following methods;

  1. Using a constructor

  2. Using a static factory method

  3. Using an instance factory method

Bean Factory

Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);

Lifecycle Callbacks

Initialization Callbacks

Implementing the org.springframework.beans.factory.InitializingBean interface provides:

void afterPropertiesSet() throws Exception;

Alternatively:

<bean id="example" class="SomeBean" init-method="init"/>

public class SomeBean {
    public void init() {
    }
}

Destruction Callbacks

Implementing the org.springframework.beans.factory.DisposableBean interface provides:

void destroy() throws Exception;

Alternatively:

<bean id="example" class="SomeBean" destory-method="destroy" />

Default Callback Naming

Applies to all beans in container. The named methods will be called if they exist.

<beans default-init-method="init" default-destroy-method="destroy">

Bean Definition Inheritance

A child bean defininition can inherit the properties of it's parent, by specifying the parent id using the parent attribute of the <bean> element.

The parent bean definition can be declared abstract by setting the abstract attribute of the <bean> element to "true". In this case, no class attribute is required.

If a child bean definition has no class specified, it takes that of the specified parent.

The depends on, autowire mode, dependency check, singleton, scope and lazy init attributes settings are always taken from the child definition.

Internationalisation using MessageSource

The Application Context will search for a MessageSource bean definition named messageSource.

To use a ResourceBundleMessageSource, define a bean similar to the following:

    <beans>
      <bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="baseNames">
          <list
            <value>resource1</value>
            <value>resource2</value>
          </list>
        </property>
      </bean>
    </beans>

This will search the classpath for two resource bundles named resource1 and resource2. Alternative language versions are named for example resource1enGB.properties.

Resources are then retrieved using MessageSource.getMessage(...) calls.

The MessageSourceAware interface can be used to inject any implementing bean with the application's MessageSource.

Spring also provides a ReloadableResourceBundleMessageSource that is more flexible than the JDK based ResouceBundleMessageSource.

Events

Beans can implement the ApplicationListener interface to handle various events within the ApplicationContext.

Low-level Resources

An ApplicationContext is also a ResourceLoader which can load Resources from any location, e.g. the file system, classpath or URL.

Web Application Context

    <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value>
    </context-param>
    <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!-- or use the ContextLoaderServlet instead of the above listener
    <servlet>
      <servlet-name>context</servlet-name>
      <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
    </servlet>
    -->

/WEB-INF/applicationContext.xml is used as the default if no value is specified for the contextConfigLocation. Ant style path patterns can also be used to specify application contexts.

TODO:: continue from 3.9 Glue code and the evil singleton

HTML Escaping

Set a "defaultHtmlEscape" web.xml context-param specifying the default behaviour.

Use org.springframework.web.servlet.tags.HtmlEscapeTag on a per page basis to override the default behaviour.

Note: The HTML escaping is only done when the page is rendered. Input values submitted in a POST or GET or submittted AS-IS.

Submitting Indexed Properties

This requires much the same solution as described in StrutsHints with indexed properties being rendered in the HTML in the following JSTL fashion:

<table>
<c:set value="0" var="i" />
<c:forEach varStatus="loop" var="item" items="${model.myList}">
<tr>
<td><c:out value="${item.myValue}" /> </td>
<td><input type="hidden" name="<c:out value="submitValue[${loop.index}].id" />" value="<c:out value="${item.id}" />" />
<input type="radio" name="<c:out value="submitValue[${loop.index}].choice" />" value="Selected" checked="checked"/></td>
</tr>
</c:forEach>
</table>

The indexed properties will be written to a list property named 'submitValue'

Error Handling

org.springframework.web.servlet.tags.form.ErrorsTag.MESSAGES_ATTRIBUTE is used to define where error messages are stored within the page context. Whilst this could change, it is currently, "messages"

Sharing Session Data Between Portlets

See http://opensource.atlassian.com/confluence/spring/pages/viewpage.action?pageId=3131

References

Related Topics:: StrutsHints

-- Frank Dean - 16 Aug 2007