0
0
0
13,036

Tutorial on Spring Bean Container

Tutorial on Spring Bean Container and Dependency Injection

Abstract

SpringMVC This is a Tutorial on the Spring Bean Container and Dependency-Injection with XML and annotations.

Introduction

The core of Spring Framework is a container that manages the life-cycle of application components. Following the Java convention, Spring calls the application components as beans, thus the term bean container is often used. Managing beans includes creating instances of the beans from configuration instructions, configuring the beans and automatically inject dependencies between, notify the beans about life-cycle events such as creation and destruction, and create bean adaptors (proxys) that can be used to implement specific features,

Java beans are assumed to define defines public setter and getter methods to modify and access object properties. These property setters are used by the bean container to configure the bean before its ready to be used by the application.

One great advantage of using a bean container to configure the application, is that the dependencies between components are externalize or removed from the Java code. In the limit case where configuration of all dependencies is made outside the components code, one says that occurred an inversion of control on the system. Developing an application according the inversion of control principle also promotes programming to interfaces, since components express their dependencies on service interfaces and not on specific class implementation. This two aspects make much easier to reconfigure the application, such as when moving from testing and deployment phases or when changing running environment. Refactoring is also simplified since components can not make too much assumptions about the ways interfaces are actually implemented.

Figure below illustrates the process by which a bean container creates two beans from configuration instructions, and injects a dependency between the two beans. In particular, bean A automatically gets a reference to bean B without explicitly asking for it or creating it.

Container creates beans and performs dependency injection as specified in configuration instructions.

Most often applications are made not of two by of many components that have dependencies between them, and dependencies to the underlying infrastructure. Thus, the bean container needs to read configuration instructions and assemble the full application in a possible complex network of dependencies. Only after the application is fully configured is the business logic allowed to making invocations to services defined in the components.

Container creates beans and performs dependency injection as specifies in configuration instructions.

In Spring Framework, definition and configuration of application beans can be done using one of two languages: XML tags referring Java classes (available since Spring1.0); and Java annotations driving the configuration (requires Java5, and available since Spring2.0). In the presentation below, we start by using the classing approach to Spring configuration based on XML and them move to annotation driven configuration.

XML Based Configuration

Spring Beans files are XML files used to define the beans and configuration of an application. They should have the structure of a well-formed XML standard be follow: namely, start with directive <?xml version="..">, and have a valid top-level enclosing tag. The files should also import XML namespaces that recognized by Spring Framework. The most commonly used namespace is the <beans:*> namespace, that is used to declared and configure individual beans. XML snippet bellow illustrates the typical structure of a XML Spring bean file.

<?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-3.0.xsd">

<!-- bean definitions go here --->

</beans>

If some tags have the form <pp:*> than a correponsing namespace should be defined with name pp. This is done with attribute xmlns:pp, for namespace prefixed with <pp:*>. If an imported namespace is to be the default namespave (so that the tags prefix is not required) then the attribute xmlns is used. The location of the scheme may optionally be provided with attribute xsi:schemaLocation, and the format of the scheme should be defined with attribute xmlns:xsi. (Namespaces are only used since Spring 2.0.) In Spring configuration the beans namespace is often used as the default namespace. This is the namespace that defines the tags to define beans, configure the beans, and inject dependencies in them. For the beans namespace, the top-level XML element (tag) is always <beans>. Below, we show an example of Spring XML configuration file importing the namespace beans as default namespace:

XML Bean Definitions

Individual beans are declared in XML using the tag <bean>, usually inside the top-level tag <beans>. The attributes of the tag <bean> are used to configure the beans. Attribute id=".." specifies the container-scoped string identifier for the bean. No two beans inside the same container (or container hierarchy) may have the same identifier. Attribute class=".." specifies the fully qualified Java class name for the bean type.

Below we show the two possible XML valid ways to define a beans. The first bean, set with id myBeanId, is defined with a single XML tag (no closing tag) so that the full configuration needs to be provided using tag attributes. The second beans set with id myOtherBeanId use an opening <bean> tag and corresponding closing tag </bean>. This allows further bean configuration to be provided as additional sub-tags. Attribute class specifies that both beans are defined in Java package name pckg, and bean class names are classname1 and classname2, respectively.

<bean id="myBeanId" class="pckg.classname1" />

<bean id="myOtherBeanId" class="pckg.classname2" >
	<!-- further bean configuration should go here -->
</bean>

A often used convention is to name beans with the uncapitalized version of the class name. Thus, if one has java class named MyService then the bean name selected is myService. If there is multiple beans of the same class name, then some prefix or suffix is used to make id unique.

To create two beans with class type MyService defined in package myapp, the following XML configuration can be used:

<bean id="myService" class="myapp.MyService" />

<bean id="myService2" class="myapp.MyService">
</bean>

Bean Naming

Beans identifiers are defined with attribute id, as explained. This attribute is given a special treatement in XML standart, so that only a limited number of characters can be used. For example, caracther such as slashes, tildes, dots, and other puctuation signs are not alowed. Thus, if one run a bean configuration file through a XML validator with bean ids violoting XML rules this is going to be noticed. (The reason for these rules, is that some XML standarts such XPointer give special treatement to some symbols such as slashes a dots.)

To overcome XML limitation, Spring defines an additional attribute name that can be used to define one or more names for beans. Contrary to ids, names dont have character restriction and thus provides more naming options. When providing multiples names they should be separated by commas or spaces. Below, we show an example of a bean defined with multiple names.

<!-- alternative names (aliases with less strict naming) -->
<bean id="myBeanId" name="beans.myBean, beans/myBean" ... /> 
In all respects, other than allowed characters, ids and names have the same role. For example, when injecting a bean in some other bean, both id and any of the names can be used. Likewise, in Java container can be queryed for a bean by id or by any of its names.

Bean Configuration and Dependency Injection

Individual beans are configured in one of two ways: specifying constructor arguments, and setting property values. Constructor arguments are specified with XML tag <constructor-arg> inside the <bean> element. The attribute value is used to pass literal values, including scalar values and collections. The attribute ref is used to inject a reference to other beans. The value of the attribute should be an id or name of the bean to inject. Multiple constructor tags can be provided. However, the number and type of the values or beans should be compatible with the set of constructors defined for the bean class. If no <constructor-arg> tag is provided then the bean class needs to have a public no-arguments constructor.

Below, we show an example of a bean created with multiple constructor arguments. Two arguments are scalar values and one argument is an injected reference to other bean.

<bean id="myBean" class="myapp.packg.ClassName">
	<!-- constructor arguments with scalar values -->
	<constructor-arg value="123" /> 
	<constructor-arg value="joe" /> 	

	<!-- constructor argument with injected reference to other bean -->
	<constructor-arg ref="myOtherBean" /> 
</bean>

<bean id="myOtherBean" class="myapp.packg.OtherClassName" />

Property values are set with XML tag <property>, inside the <bean> element. The attribute name is used to specify the property name. Attributes value and ref have the same meaning as in <constructor-arg>. Defining property values makes Springs at bean configuration time call the corresponding property setter. Thus is a property is named someProperty and has type T, then the setter method called is named setSomeProperty(T).

Below, we show a bean definition example similar to the above, but this time using only property setters:

<bean id="myBean" class="myapp.packg.ClassName">
	<!-- properties set with scalar values -->
	<property name="code" value="123" /> 
	<property name="name" value="joe" /> 	

	<!-- properties injected with reference to other bean -->
	<property name="peer" ref="myOtherBean" /> 
</bean>

Constructor arguments and property setting can be intermixed freely in the bean definition, since constructor arguments are always processed earlier than property settings so no ambiguity exists. Notice that, in contrast to property setting, constructors arguments can not be distinguished by name -- only by order and type. If the argument types are all different, then Spring is smart enough to reorder arguments as needed to find a suitable constructor. On the other hand, if there exists multiple argument with the same type the order of <constructor-arg> tags should match the order in the Java class constructor.

Below, we show an example of a mixed configuration with constructor arguments and property setters:

<!-- bean configured with constructor arguments and property setters -->
<bean id="myBean" class="myapp.packg.ClassName">
	<constructor-arg value="joe" />
	<property name="code" value="123" /> 
	<property name="peer" ref="myOtherBean" /> 
</bean>

When application defined beans and request the injection of dependencies between them, the container needs to take care for objects to be created on the right order. Namely, if a bean A depends on other bean B by means of a contructor argument, then the container needs to create bean B before it creates bean A. This also applies to other beans that B depends on. Thus, in general, the bean container needs to recreated the dependency graph, and sorted accordingly so that needed beans are created earlier. This is a usually called topological ordering according to the depends-on relationship.

Figure below illustrates the ordering that the bean container induces from the bean definitions and the dependency relation defined implicitly by the injection of reference in contructor arguments:

The dependency graph is sorted so that construtor-argument induced dependencies are created earlier by the bean container.

Note that if beans can not be ordered according to the dependency relation, than an exception is thrown by the Spring container at application deployment time. This occurs in situations where there are cycles in the constuctor-induced dependency graph. Such as when a bean A depends on B, B depends on C, and C depends on A. Longer cycles are also not allowed. Note also that injection of dependencies by property values do not follows this restriction, since the ordering of injection is arbitrary.

Bean Creation with Factories

Spring provides features to created beans using factories. If the factory uses static factory method, the attribute class of the <bean> definition tag is set with the the fully-qualified name of the factory class, and the attribute factory-method takes the name of the static method. A factory class can have any number of factories methods, and each method can be used to create any number of beans. The type of created bean is the type of the return value of the factory method used. The type of the bean does not need to be the type of the factory class. This contrasts with beans defined without factories, when the type of the bean is the type specified in attribute class.

This is illustrated below:

<!-- using a static factory method-->
<bean id="aname" class="myPackage.myFactory" factory-method="getABean" /> 

Factories are useful in Spring-based application, specially when the beans Java classes do not match the requirements defined by Java Beans conventions, such as: not providing public property setter methods, not being public classes, or not having appropriated public constructors. Although, in newly crafted programs care is often taken to follow Java Beans convention, in legacy code this might not be the case.

In object-oriented programming, a factory method is a strategy to create objects. The signature of a factory method, including the type of object that it produces, is common to all implementation and is usually defined in a factory interface or abstract class.

When factory methods are non-static, a bean factory bean should be defined first. Bean instances are created by replacing attribute class by attribute factory-bean referencing the factory beans. Attribute factory-method specifies the name of the non-static factory method. The same bean factory can be used to create several beans, with same or different factory method. Below, we show an example of defining and using a factory bean to create other beans:

<!-- using a bean factory implementation -->

<bean id="myFactory" class="myPackage.MyFactory"/>

<!-- using a factory bean to create two beans -->

<bean id="myBean" factory-bean="myFactory" factory-method="getMyBean" />

<bean id="myOtherBean" factory-bean="myFactory" factory-method="createOtherBean" />

Beans created with factory methods and factory beans can also be configurable with constructor argument and properties. Constructor arguments are used as argument to the factory method, while properties are set on the created instance. This is illustrated below:

<!-- passing arguments to a factory bean -->
<bean id="myBean" factory-bean="myFactory" factory-method="getMyBean">
	<constructor-arg value="joe" />
</bean>

<!-- configuration the properties of a bean created with a factory -->
<bean id="myOtherBean" factory-bean="myFactory" factory-method="createOtherBean">
	<property name="name" value="joe" />
</bean>

An alternative way to define factory classes is by implementing the Spring interface FactoryBean<A>. The interface specification is shown below:

public interface FactoryBean<T> {
	public T getObject() throws Exception;
		public Class<T> getObjectType();
		public boolean isSingleton();
}

Method getObjectType() is used to get type of the create bean; method getObject() is used to created the bean; and method isSingleton() is used to check the scope of the bean.

Below, we shown an example of a factory class implementing the generic interface FactoryBean<T> to create instances of class MyService.

public class MyServiceFactory implements FactoryBean<MyService> {
	private static MyService service;
	private boolean singleton = false;
	
	public MyServiceFactory(boolean singleton) { this.singleton = singleton; }

	public MyServiceFactory() {}
			
	public A getObject() throws Exception {
		if (isSingleton()) {
			if (service!=null) {
				return service;
			}
			service = new MyService();
			return service;
		 }
		return new MyService();
	}

	public Class<A?> getObjectType() { return MyService.class; }

	public boolean isSingleton() { return singleton; }
}

To create a bean with the factory we need to declared the factory as a Spring bean. Below, we shown an example of defining a bean factory and creating a bean using that factory. Constructor arguments is used to configure the factory. Properties are set of the created bean instance.

<!-- using a bean factory implementation -->
<bean id="aFactory" class="myPackage.AFactory"/>

<!-- using the factory and configuring the create bean-->
<bean id="aFactory" class="myPackage.AFactory">
	<constructor-arg value="true" />
	<propety name="code" value="123" />
</bean>

Bean Configuration Summary

Table below shows a summary of the attributes allowed for the tag <bean>. Several of these attributes have already been discussed, while other are to be described in following sections.

Attribute Value Type Description
id XML valid ID identifier/name for the bean
name list of names alias for the bean (alternative names)
class fully qualified class name bean type
init-method method name init callback
destroy-method method name destroy callback
depends-on bean-ref explicit dependency
lazy-init true|false delay bean creation until lookup
autowire no|byName|byType|constructor|autodetect criteria to use in auto-wiring
dependency-check none|simple|object|all where to inject dependencies
scope singleton|prototype|request|session|globalSession scope of bean
factory-method method name method that creates bean
factory-bean bean name bean factory bean
parent bean name bean to inherit definitions from
abstract true|false bean definition is a template
autowire-canditate true|false May be injected?
Summary of attributes for the <bean> tag.

Injection of Java Collections

The simplest scenario when setting a property or constructor-argument value is the use of scalar types (e.g. primitive and wrapper types, strings, and other types recognized by Spring such as dates). It is also possible to set property and constructor-argument values as java collections. This includes lists, sets, and maps. Different XML tags are used for the different types of collections.

Tag <list> is used to defined list collections. This corresponds to create an object of type java.util.ArrayList. Any type of element can be inserted in the list, including other collections. Different types of values are also allowed. The elements to insert in the list are defined in additional XML sub-tag. The tag ref is used to insert a reference to a bean, with a atrribute ref specifying the id or name of the bean. The tag value is used to insert a scalar value on the list or other collection. The actual value can be provided as attribute value or can be provided as the text body of the tag.

Below, we show an example of setting a bean property with a list value, whose elements include scalar values, bean references, and a list with bean references:

<bean id="myBean" ... >
	<property name="someProp">
		<list>
			<ref bean="myOtherBean"/>	
			<value value="123" />
			<value value="abc" />
			<value>123</value>
			<value>abc</value>
			<list>
				<ref bean="otherBean"/>
				<ref bean="someOtherBean"/>
			</list>
		</list>
	</property> 
</bean>

To create set collections the XML tag <set> should be used. This corresponds to create an object of type java.util.Set. Values are inserted the same way as in list collections, namely, with tag <ref> for bean elements, and tag <value> for scalar or simple values.

Below, we show an example of a bean whose constructor argument takes a set collection as value:
<bean id="myBean" ... >
	<constructor-arg>
		<set>
				<ref bean="myOtherBean"/>
				<value value="abc"/>
				<list>
					<value>123</value>
					<value>345</value> 
				</list>	
			</set>
	</constructor-arg>
</bean>

Java maps can also be defined as values for properties and constructors. This is done with XML tag map. Individual entries are defined with tag <entry>. Attribute key defines the key of the entry and attribute value defines the value of the entry. Values and keys can also be defined inside the entry body with tags key and value.

Below, we shown an example of a property set with a map value:

<bean id="myBean" ... >
	<property name="people">
		<map>
			<entry key="joe" value="123"/>
			<entry key="jack">
				<value>345</value>
			</entry>
			<entry value="345">
				<key>mary</key>
			</entry>
			<entry>
				<key>jenny</key>
				<value>789</value>
			</entry>
		</map>
	</property> 
</bean>

Java property objects can also be defined in Spring configuration. The object created is of type java.util.Properties. The XML tag props is used to created the properties container (not to be confused with the beans property tag). Individual property name--value pairs (entries) are defined with tag prop. The name and value of the entries are defined the same way as entries for maps.

Below, we show an example how to defined a Java Properties value:

<bean id="myBean" ... >
	<property name="myprops">
		<props>
			<prop key="locale.language">english</prop>
			<prop key="locale.country">UK</prop>
		</props>
	</prop>
</property>	

Container Creation and Termination

To use the Spring dependency-injection mechaninsms, an instance of a Spring bean container needs to be created first. This is any object whose class implements the BeanFactory interface or any derived interface. In standalone Java application the bean container is often done explicitly by the application. For web-application the application infrastructure is setup in a way that the bean container. In testing phase is also possible to use a Spring provided Spring engine that automatically creates bean containers as needed.

The interface ApplicationContext derives the BeanFactory interface to provides additional services, not all specific with bean management. Several classes implement the ApplicationContext interface, such as AbstractXmlApplicationContext that allows the Spring container to be configured with XML files.

Concrete class ClassPathXmlApplicationContext further derives the abstract class AbstractXmlApplicationContext, and provides a convinient way to load XML configuration accessible from class-path directories. One or more file names can be provided, using an array or variable argument-list with file locations. A Spring Framework beast-pratice is to keep infrastructure-specific and common application configuration in separated files. This allows easy migration or changing the infrastucture components while keeping the common configuration unchanged. Configuration specific to testing is also kept in separated configuration file.

An alternative class FileSystemXmlApplicationContext locates XML configuration files from the root of the filesystem. The location strategy for configuration files can also be as a file name prefix, such as: classpath:, file:, or http:.

Below, we show an example of creating a bean container in a standalone application:

//search classpath for configuration files
ApplicationContext ctx = 
	new ClassPathXmlApplicationContext("config/myConfiguration.xml",
	"file:myapps/config/myInfrastructure.xml");

The constructor of the bean container return only when the application is fully configured, as specified in the XML configuration files. This includes creation and configuration of beans, injection of dependencies, creation of bean proxies, and notifying beans of life-cyle eventes.

Application contexts can be setup in parent-child relations, such that the child container can access the beans defined in the parent container. The parent of a container is often specified a constructor argument. Below, we show an example of creating two bean containers with a parent-child relation to be used in a standalone application.

ApplicationContext parentContext =
	new ClassPathXmlApplicationContext("myInfrastructue.xml"); 

ApplicationContext childContext = 
	new ClassPathXmlApplicationContext(new String[] {"config1.xml", "config2.xml"</b>,
		parentContext); 
The ConfigurableApplicationContext interface additionally extends the ApplicationContext to declare additional method, such as container shutdown support. In particular, method close() forces the bean container to destroy application beans and terminate. All classes described above implement also this interface. Below, we show the bean container can be explicitly shutdown:
//create bean container and configure the application
ConfigurableApplicationContext ctx =
	new ClassPathXmlApplicationContext("applicationConfig.xml");

//use application
//... 
//terminate application
ctx.close(); 

Bean Lookup

References to beans are most ofent injected automatically by the container according to the dependencies expresses in other beans. There cases, however, where it is desirable to interact directlu with the bean container to get a specific bean according to its name, type, or both. This is done with overloaded methods getBean() defined in interface FactoryBean. This interface is implemented by ApplicationContext classes. Below, we show the specification of theFactoryBean with only a selected sub-set of methods:

interface FactoryBean {
	boolean containsBean(String name);

	<T> T getBean(Class<T> type) throws BeansException;

	Object 	getBean(String name) throws BeansException;

	<T> T getBean(String name, Class<T> type) throws BeansException;

	... }

Below, we show examples how to get beans by name and type. If a bean with specified name is not found an exception is thrown. Likewise, if no bean of a matching type is found an exception is also thrown. When both name and type are provided an additional check is made for type matching. In the example the bean type is class A.

ApplicationContext ctx = ... 
A a = (A) ctx.getBean("beanName");
	
a = ctx.getBean("beanName", A.class); 

a = ctx.getBean(A.class);

Bean Life-cycle Call-Backs

Beans can be notified after creation and all properties are set, and before they are destroyed and removed from the bean container. This involves specifying the callback method to be invoked by the container. This is done in XML by specifying attributes init-method="myinit", for the initialization callback, and destroy-method="mydestroy", for the destroy callback. "myinit" and "mydestroy" are names of instance methods in the bean class.

<bean id="abean" class="packg.classname" init-method="myinit">...</bean>
<bean id="abean" class="packg.classname" destroy-method="mydestroy">...</bean>

Starting with Spring 2.5, Java annotations can also be used to declare life-cycle callbacks.

public class A {
	//init callback
	@PostConstruct
	void init() { ... </h2>

	//destroy callback
	@PreDestroy
	void destroy() { ... }
}

Additionally, a Java bean class can implement interfaces InitializingBean and/or DisposableBean and its methods, to get call-backed on life-cycle events.

import org.springframework.beans.factory.*;

public class A implements InitializingBean {
	public void afterPropertiesSet() { ... }
}

public class A implements DisposableBean {
	public void destroy() { ... }
}

When several initialization and or destroy callbacks functions are setup the following invocation orders apply:

InitializationDestruction
  1. @PostConstruct
  2. InitializingBean.afterPropertiesSet()
  3. <bean init-method=".."/> XML attribute
  1. @PreDestroy
  2. DisposableBean.destroy()
  3. <bean destroy-method=".."/> XML attribute

Enabling Annotation Processing

To enable annotation processing the XML tag <context:annotation-config/> should be included in the container configuration file.
<!--activate annotations processing; enables multiple BeanPostProcessors -->
<context:annotation-config/> 

Bean Scopes

A bean scope specifies when a bean is created or reused -- its creation policy. By default, bean are singletons, i.e. a single bean instance is created and mantained by the container. If multiple requests for the same bean are made, the same instance is returned or injected by the container. The attribute scope="..." configures the bean scope.

<bean id="abean" class="package.classname"
	scope="singleton|prototype|{session|request</b>.>...</bean>
  • singleton -- Single instance is created (default)
  • prototype -- A new instance is created each time the bean is referenced
  • session -- A new instance is created once per user session (web) -- implemented with <aop:scoped-proxy/>
  • request -- A new instance is created once per request (web)
  • custom -- New scopes can also be implemented by applications.

Initialization Constraints

Constraints on bean properties include forcing it to be injected with an appropriate bean. This is done using annotation @Required.

@Required void setB(B b) {...</b> //mandatory dependency

Inheritance of Beans Definitions

Its possible to implement parent--child relations between beans to afford inheritance of property values. Beans with attribute parent="abase", declare that the inherit configuration values from a parent bean named abase. A parent bean can be declared abstract with attribute abstract="true", if it does not correspond any Java object, but is rather used for the sake of economy of description.

<!-- abstract parent bean: not to be instantiated -->
<bean id="baseA" class="package.classname" abstract="true">
	<property name="a" value="aa" />
</bean>													 
<bean id="derivedB" parent="baseA">
	<!--extending parent with an extra property value setting-->
	<property name="b" value="bb" />
</bean>
<bean id="derivedC" parent="baseA">
	<!--overriding parent on setter argument value-->
	<property name="a" value="abc" />
</bean>

Inner Beans

Bean can be inject with private anonymous beans:

<bean id="root"	class="package.classname">
	<property name="aa">
	<!-- replaces need to use ref="namedbean" -->
	<bean class="package2.classname2"> ... </bean>
	</property>
</bean>

Arbitrary recursion level are also possible in defining anonymous beans. Although, XML notation for bean configuration may become too confusing if a higher number of nesting is used. XML source below shown an example:

<bean id="topBean" class="pckg.classname">
	<property name="aa">
	<bean class="pckg2.classname2">
		<constructor-arg>
			<!-- two-level deep anonymous inner bean -->
			<bean class="pckg3.classname3"> ... </bean> 
		</constructor-arg> 
	</bean>
	</property>
</bean>

XML Imports

To split and combine XML configuration information across several XML file, used the tag <import resource="filename.xml"/>. An example is shown below:

<!--file a.xml: -->
<import resource="path/b.xml" />
<import resource="classpath:com/company/c.xml"" />

Bean and BeanFactory Post-Processing

Applications can modify the details of bean creation process by implementing interface BeanFactoryPostProcessor. This interface specifies callback methods where language-neutral bean definitions can be modified before the container creates the actual beans. An example provided by Spring Framework is PropertyPlaceholderConfigurer, that is responsible to replace values of the form ${prop}. to actual values from a property file. This is configured as shown follows:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="location" value="/WEB-INF/myprops.properties" />
</bean>

Since this bean is very commonly used the tag <context:property-placeholder> can be used as a short replacement, as follows:

<context:property-placeholder location="/WEB-INF/myprops.properties" />

After bean definitions are loaded and BeanFactoryPostProcessor invoked, bean are eagerly instantiated by default. The attribute lazy-init="true", can be used to delay bean creation until actually needed (erg. for dependency injection). Instantiation includes object creation, invocation of setter method, and invocation of initialization callbacks. The right order of instantiation is used to preserve dependency injection semantics. After all this is done, each bean goes through a further post-processing phase. This includes invoking objects implementing the interface BeanPostProcessor. Example bean post-processors provided with Spring include: CommonAnnotationBeanPostProcessor --- that handle common annotation such as @Autowired, @PostConstruct, @PreDestroy, and RequiredAnnotationBeanPostProcessor that handles the annotation such @Required. As pointed out, XML tag <context:annotation-config/> automatically enables these two bean post-processor. Otherwise, they can be installed by defining anonymous beans that have the respective class type, as shown below:

<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<bean class="org.springframework.context.annotation.RequiredAnnotationBeanPostProcessor" />
Invocation of bean post-processors is the last step in deployment of a bean container. After this step, beans are ready to be used by the application. The full list of container and bean initialization steps is summarized below:
  1. Read bean file XML and/or process annotations
  2. Build internal "map" of beans and determine dependency tree
  3. Post-process the definitions --- e.g. resolve ${vars}
  4. Allocate objects --- dependency inject constructor args and invoke setter
  5. Perform initialization --- @PostConstruct, InitializingBean, init-method
  6. Bean post-processors --- e.g. wrap with proxy (in AOP and transactions), check @Required

Figure illustrates the process by which a BeanFactoryPostProcessor modifies bean definitions, and a BeanPostProcessor replaces bean instances.

A BeanFactoryPostProcessor modifies bean definitions, while a BeanPostProcessor replaces bean instances (such as when creating a proxy)

Type Conversion

Property Editors

In addition to atomic and simple Java types, and collections, it also possible to use other string to object converter in value settings using a PropertyEditor.

Example below show the use of a rich string value that is converted to a object of class A before injecting property named pat.

<bean id="abean"	class="package.classname">
	<!--custom value string mapped to object --> 
	<property name="pat" value="[0-9]{3</b>.[0-9]{3</b>.[0-9]{4</b>.
/>
</bean>
public class A {
	Pattern pat;

	//rich object argument	
	public void setPattern(Pattern pat) { this.pat = pat; }
}

To make automatic conversion of strings to new types possible, an appropriate property editor must be registered in the bean container.

Regestering Property Editors

Below, we show an example of configuring and registering a PropertyEditor to handle the type java.util.Date.

<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
	<property name="customEditors">
	<map>
		<entry key="java.util.Date">
			<bean class="org.springframework.beans.propertyeditors.CustomDateEditor">
				<constructor-arg>
					<bean class="java.text.SimpleDateFormat">
						<constructor-arg value="yyyy-MM-dd"/>
					</bean>
				</constructor-arg>
				<constructor-arg value="false"/>
			</bean>
		</entry>
	</map>
	</property>
</bean>

Default and Provided Property Editors

Spring Framework provide as set of built-in property editors summarized in Table below. For example, PropertiesEditor can handle property values as (property, value) pairs, like: <value> prop1=val1 prop2=val2 </value>, and convert to a java.util.Properties object; while PatternEditor can handle regular expression like "a[bc]d*1.?", and convert it to a javax.util.regex.Pattern.

Property EditorType(s)Description
CustomNumberEditor Number numeric types
CustomBooleanEditor Boolean
CustomDateEditor java.util.Date
ResourceBundleEditor Resource
PropertiesEditor java.util.Properties Java Properties
ByteArrayPropertyEditor byte[]
LocaleEditor java.util.Locale Internationalization
PatternEditor (SF2.0.1) javax.util.regex.Pattern Regular Expressions
Build-in property editors

Custom Property Editors

It also possible to create application custom property editors by implementing interface PropertyEditorSupport.

import org.springframework.beans.propertyeditor.*;

public class AEditor extends PropertyEditorSupport {
	public void setAsText(String s) {
		setValue(s!=null ? A.fromString(s) : null);
	</h2>

	public String getAsText() {
		A v = (A) getValue();
		return (v != null ? v.toString() : "");
	}
}
Registration of a custom property editor is done by setting an map entry in a bean of build-in type CustomEditorConfigurer. See example below:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
	<property name="customEditors">
	<map>
	<entry key="pckg1.A" value="pckg2.AEditor" />
	</map>
	</property>
</bean>

XML Namespaces

In Spring Framework XML namespaces define sets of XML elements that can be used to configure of an application. To use a namespace a template skeleton like the one shown below should be used. The actual namespace replaces the \_\_ .

xmlns:__="http://www.springframework.org/schema1/__"
xsi:schemaLocation="http://www.springframework.org/schema/___
				http://www.springframework.org/schema/___/spring-__-3.0.xsd">

Namespace: beans

Namespace beans provides the elements used in the definition of beans. The XML skeleton below shows how the beans namespace can be used as a default namespace inside the top-level element <beans:beans>.

<?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-3.0.xsd">
.... </beans>

Table below summarizes the available XML tags or elements and its attributes. Identation is used to suggest the depth an element is usually used.

Tag <bean:*>AttributesSub-tagsDescription
<beans> <bean> top-level element
<bean> (see above) <property|constructor-arg> define managed bean
<property> name|value|ref <list|set|map> define property value
<constructor-arg> value|ref|type|index <list|set|map> define constructor argument
<list> merge <value|ref> define List collection value
<set> merge <value|ref> define Set collection value
<ref> beanlocalparent bean reference value
<value> value simple or rich value
<idref> beanlocal|parent bean name value
<map> merge <value|ref> define Map collection value
<entry> keyvaluevalue-ref <key|value> map entry
<key> key for map entry
<props> merge <prop> define Properties value
<prop> key define property value
<null> null value
Summary of tags and attributes for the XML namespace <bean>.

Namespace: context

Namespace context defines XML elements used for configuration of the bean container. The prefix usually used for tags is <context:*>. As an example, XML tag <context:property-placeholder> is used to load a properties file. This is equivalent to create a bean of type PropertyPlaceholderConfigurer. Property location is used to specify the location of the property file.

<!-- using context namespace -->
<context:property-placeholder location="filename.properties" />

<!-- explicit creation of property configuration bean -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
	<property name="location" value="filename.properties" />
/bean>

Table summarizes the tags and attributes defined by namespace context.

Tag <context:*> Attributes Sub-tags Description
<annotation-config> Activate annotations processing
<property-placeholder> location <value> Property file
<component-scan> base-package <include-filter>|<exclude-filter> Auto-scan package tree for managed beans
<include-filter> type|expression Auto-scan inclusion criteria
<exclude-filter> type|expression Auto-scan exclusion criteria
<mbean-server> Locate or create JMX MBean Server
<mbean-export> Export MBeans
Summary of tags and attributes for the XML namespace <context>.

Namespace: p

Namespace p is pseudo-namespace used as a shortway to set property values. When this namespace is imported, bean attributes with the selected prefix (usually p. are used to set bean property values in less verbose way than with the tag <property>. A bean attribute with name p:propName="value" is interpreted as the configuration of a property named propName. The attribute value is the value to set for the property. This value is interpreted as a scalar value. For properties that take bean references the attribute name pattern should be p:propName-ref="beanName".

Below, we show some example of setting bean properties with the p namespace.

<!-- tag prefix is removed to get property name -->
<bean id="a1" class="..." p:aa="v" /> 

<!-- tag prefix and suffix is removed to get property name -->
<bean id="a2" class="..." p:bb-ref="abean" />

<!-- The same configuration can be done with -->
<bean id="a3" class="...">
	<property name="aa" value="v"/>
</bean>
<bean id="a4" class="...">
	<property name="bb" ref="abean"/>
</bean>

The p namespace is imported by adding the attribute xmlns:p="http://www.springframework.org/schema/p". No schemaLocation can or should be provided for this namespace. This is because, a XML schema defines a set valid XML elements and their attributes. Since attribute names depend on application-specific names, there is no possima schema that can be provided.

Namespace: util

Define <util:*> tags, defining a set of utilities such as: java collections initialization, static constant access, and other. <util:list>, <util:set>, <util:map> have similar meaning as the contra-parts form the default beans name-space, but provide additional options to specific the java container class used, and the allowed element type. Table below summarizes the available tags and its attributes.

<property name="aa">
<!-- List<A> value -->
	<util:list list-class="java.util.ArrayList" value-type="package.A">
	<ref bean="bb" />
	<bean class="packg.ADerived" ... />
	</util:list>
</property>

<!-- set collection as top-level bean -->
<util:set id="aset"> 
	<value>aa</value>
	<value>bb</value>
	<value>cc</value>
</util:set>

<bean id="a" class="package.classname">
	<!--get set reference-->
	<property name="aa" ref="aset"/>
</bean> 

<util:map>
	<!--value for first map entry is a top-level named bean ->
	<entry key="key1" value-ref="bean1" />
	<!-- second entry is anonymous inner bean ->	
	<entry key="key2"><bean class="package.classname" .../></entry>
	<!--third entry as bean key-->
	<entry>
		<key><bean class=".."><constructor-arg ... /></bean></key>
		<bean .../>
	 </entry> 
</util:map>

The <util:constant> tag is used to access a constant value (static final field):


<b><!-- final static field value access (constant) --> 
<util:constant static-field="packg.MyConstants.CONST_NAME" /> 
Additional properties--value files, with standard Java property file-format, can be specified with tag <util:properties>:
<!-- load a Java Property file -->
<util:properties location="classpath:afilename.properties" /> 
Tag <util:*> Attributes Sub-tags Description
<list> <value> <ref> define List collection value
<set> <value> <ref> define Set collection value
<map> <value> <ref> define Map collection value
<constant> static-field Java constant value
<properties> location Load property file
Summary of tags and attributes for the XML name-space <util>.

Annotation-Driven Configuration

Java annotations are used in Spring Framework to configure an application with Java Syntax, possible in the same set of source files as the main application logic.

Java based @Configuration annotated classes, while providing flexibility and control, put much effort on the application programmer. Spring Framework provides additional annotations to specify in Java classes where and what beans should be injected, thus simplifying configuration setup while keeping XML compact. Bean definition still need to be defined, using XML or a @Configuration class.

The annotation @Autowired is used to specify that a property setter method of a data-field should be inject with a bean of appropriate type (the single argument type of the method). Bean injection is resolved by selecting a bean inside the container of the right type. If more than one bean of the same type registered in the container, an no mechanism is used for disambiguation, an error is thrown as a Java exception.

If the annotation @Qualifier("bb") is used, the identity of the inject bean is narrowed to have the specified name. The bean name is the identifier (or name alias) specified in a XML config file, or using the name specified in the annotation @Component or a derived one (see below).

Dependency injection of a property can be made mandatory, by specifying the @Required annotation (explained above). Alternatively, one can specify a required attribute in the @Autowired, as follows: @Autowired(required={false|true})..

Properties and data-fields can also also be injected with non-bean values, such as simple types and other objects, by specifying the annotation @Value("...").). The conversion between the string representation of the value and the Java object or value to be injected uses the set of registered Property Editor (as in XML). SpEL expression can also be used as value. Parameter value of other public methods, other than setters, can also be annotated with @Value("...").

Example of requesting dependency injection using annotations:
public class A {

	//automatic selection of injected bean (by type)
	@Autowired 
	void setB(B b) { ... </h2>

	//auto-wiring and qualifier in data-field
	@Autowired @Qualifier("bb") b;

	//required=true same as @Required
	@Autowired(required=false)
	void setB(@Qualifier("aa") B b) { ... </h2>

	//@Autowired applicable to generic methods (not only setters)
	@Autowired void f(C c, D d) { ... </h2>

	@Autowired
	void f(@Qualifier("aa") A a, @Qualifier("bb") B b) { ... </h2>

	//value setting (using SpEL)
	@Value("#{systemProperties['aa']</b>.)
	private A a;
	
	@Value("#{systemProperties['aa]</b>.)
	public void setA(A a) { ... </h2>

	@Autowired public void f(A a,
	@Value("#{systemProperties['aa'] </b>.) A a);

}

Component/Bean definition

Beans can be fully defined in a Java source file, by using the @Component annotation with a Java class definition. The component bean can given a name as an argument to the annotation as @Component("beanname"). The scope of the bean can be specified with the annotation @Scope("scope"). To deal with bean resolution ambiguities, the annotation @Primary can be used to give primacy of selection to the annotated bean.

@Component("bean-name")	//defines bean; name is optional
@Scope("prototype")	//optional
@Primary 			//optional
public class A implements A0 {
	@Autowired public A(B b) { ...}
	... }

Component/Bean Scanning

To specify where a Bean container should look for @Component annotation, a base package is setup for search with tag: <context:component-scan base-package="mypackage">. Bean candidates can be further narrowed, by using an inclusion filer <context:include-filter> and an exclusion filter <context:exclude-filter>. The attributes type and expression for filters, specifies the type of expression and the actual filter expression.

<!-- auto-scan package for component beans -->
<context:component-scan base-package="pckg">

	<!-- inclusion: positive constraint -->
	<context:include-filter type="regex" expression=".*A.*BB"/> 

	<!-- exclusion: negative constraint -->
	<context:exclude-filter type="annotation" expression="packg.myAnnotation"/>

</context:component-scan> 

Java Based Configuration

A low-level but highly flexible way to configure Spring Framework, is to use configuration classes annotated with @Configuration. A configuration class can also import all the bean definition from other configuration classes using the annotation @Import.

Inside a configuration class, public methods annotated with @Bean are interpreted as factory methods for beans. Beans take the same name as the factory method, and the class type is the return type of the method. Additional bean properties can be specified with additional method annotations. Annotation @Scope("beanscope") is used to specify the scope. Attribute values for @Bean are also used to specify additional bean configuration. @Bean(destroyMethod="mydestroy") is used to register the destroy callback.

Dependency injection is made explicit my have @Bean selecting the types of bean constructor argument. Properties should also be set with basic values, or anonymous objects (not bean), and other beans created by @Bean methods. Configuration class should work to keep scope semantics correct (e.g. to avoid create several instance of a singleton bean).

//configuration class annotation (1+)
@Configuration
//import and merge configuration classes
@Import({MyAppConfig2.class, MyAppConfig3.class</b>.
public class MyAppConfig {

	@Bean	 //bean definition using factory method
	public AA aA() { //bean name same as method names
	AA a = new AA();
	a.setBProp(bB()); //inject other bean as property value
	return a;
	</h2>

	@Bean
	@Scope("prototype") //set bean scope (singleton is default)
	public BB bB()
		{ return myFactory().getObject(); </b> //use factory

	//destroy callback set using annotation attributes
	//(init not needed; called in factory method)
	@Bean(destroyMethod="close")
	public MyFactory myFactory() { return new MyFactory(); }
}

Activating annotation-processing by IOC bean container needs to be made explicit, as follows:

<context:annotation-config/> (plus XML Namespace context )

<!--register configuration bean->
<bean class="pckg.MyAppConfig"/>
Injection in XML defined beans:
<bean id="aa" class="...">
	<!-- use bean definition from Java (annotated with @Bean) -->
	<constructor-arg ref="aA" />
</bean>

Summary of Annotations

Table below summaries the annotations defined by Spring Framework for the purpose of defining beans and perform dependency injection.

Annotation Description
@Autowired automatic selection of injected bean (by type)
@Qualifier("name") Constrain injected bean (to have a given name/qualifier)
@Primary Give primacy to this bean (to solve type ambiguity)
@Resource("name") same as @Autowired @Qualifier("name") (JSR-250)
@Value Inject value (not bean)
@Component Bean definition from POJO
@Repository data-access bean class
@Service service bean class
@Controller web presentation class
@Configuration Define config class
@Import Import config class (use with @Configuration)
@Bean Bean definition (inside @Configuration or @Component)
@Scope Bean scope (use with @Bean or @Component)
@Required Dependency injection mandatory
@Scheduled(fixedDelay=dt) Repeated method execution with fixed time interval
@Async Run method on different thread
@Transactional Declare transactional method
@PostConstruct Post-constructor callback
@PreDestroy Pre-destroy callback
Bean definition annotations in Spring Framework.

Stereotype Annotations

@Service
@Transactional(timeout=60)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyBeanKind {
	String value() default "";	//annotation value
}

//gets all meta-annotations (annotations on @MyBeanKind)
@MyBeanKind class A { ... }
...to detail...

Spring Expression Language (SpEL)

SpEl is a scripting language develop by SpringSource and shipped with Spring Framework. SpEl takes inspirations from WebFlow EL and JEE unified EL (superset).

Usage scenarios for SpEL:

  • XML: bean properties and constructor argument values
  • Java annotations: attribute values
  • Application support dynamic language
Using SpEl for global implicit references:
"#{systemProperties.aaa} "#{systemEnvironment.bbb}
Using SpEl for custom references:
<util:properties id="myprops" location="classpath:myprops.properties"/>

<bean ... >
	<property name="prop" value= "#{myprops.ccc}/> 
</bean>
...to detail...

No Comments

Post First Comment

Login (or Register)
Contribute Feedback