- Spring uses Dependency injection in order to link components.
- The software components that Srping uses to build applications are called beans and are nothing more than Plain Old Java Objects (POJOs), that are created, initialized, assembled and managed by the Spring Inversion of Control
- The beans definitions that make up a Spring application are provided using:
- Xml files
- Annotations from Spring 2.5 -
@Component
,@Service
,@Respository
- Java-based configuration annotation from Spring 3 -
@Bean
,@Configuration
- Mix of the above methods
- In order to read, create and manage beans it is neccesary add the following dependencies to the project:
- spring-core: fundamental parts of Spring Framework
- spring-beans: together with spring-core is the framework core
- spring-context: helps to build and use application context
- spring-context-support: support for integration with third party libraries
- spring-expressions: Expression language (SpEL) used for query and manipulate objects from external sources and use them for instance to initialize a bean
- The xml file use certain namespaces.
- The bean definition specifies de bean id, name, alias, type arguments used for initialization, dependencies and many more intems.
- The namespace has a matchin XSD that have to be added to the
<beans>
element - Example of XML configuration with a bean with Id=simpleBean:
<?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.xsd">
<bean id="simpleBean" class="com.ps.beans.SimpleBeanImpl"/>
</beans>
- The dependency injection has different mechanism to be implemented:
- via constructor
- via setter
- via field injection using only annotations
- In order to define the dependencies between beans we can do it in the following with Constructor Injection:
<beans ...>
<bean id="complexBean" class="com.ps.beans.ctr.ComplexBeanImpl">
<constructor-arg ref="simpleBean"/>
<constructor-arg value="true"
</bean>
<bean id="complexBean2" class="com.ps.beans.ctr.ComplexBeanImpl2">
<constructor-arg ref="simpleBean" index="0"/>
<constructor-arg value="true" index="1"
</bean>
<bean id= "simpleBean" class="com.ps.beans.SimpleBeanImpl"/>
</beans>
This code es equivalent to the following:
public class ComplexBeanImpl implements ComplexBean {
private SimpleBean simpleBean;
public ComplexBeanImpl(SimpleBean simpleBean, boolean complex) {
this.simpleBean = simpleBean;
this.complex = complex;
}
...
}
public class ComplexBeanImpl2 implements ComplexBean {
private SimpleBean simpleBean;
public ComplexBeanImpl(SimpleBean simpleBean, boolean complex) {
this.simpleBean = simpleBean;
this.complex = complex;
}
...
}
- The constructor injection is suitable when:
- it is mandatory for dependencies to be provied for another beans
- a bean needs to be inmutable
- due to third party library requirements
- The dependency injection instanciated and initialized a bean in a single step.
constructor-arg
is too long and it could be simplifies using the c-namespace
- In order to use setter injection, the class type of the bean must have setter methods to set the dependecies
- If a constructor with no arguments is defined Spring will use it to instanciate the bean and setter method to inject the dependencies
- A mix of constructor injection and setter injection is also possible
- The bean combining both methods looks like this:
- If a constructor with parameters is defined Spring will use it to instanciate the bean and setter method to inject the dependencies
- The bean with argument injection looks like this:
<beans ...>
<bean id="simpleBean0" class="com.ps.beans.SimpleBeanImpl"/>
<bean id="complexBean" class="com.ps.beans.set.ComplexBeanImpl">
<property name="simpleBean" ref="simpleBean"/>
</bean>
</beans>
- At class level it looks like this:
public class ComplexBeanImpl implements ComplexBean {
private SimpleBean simpleBean;
// no-argument empty constructor, not mandatory
public ComplexBeanImpl() {}
public void setSimpleBean(SimpleBean simpleBean) {
this.simpleBean = simpleBean;
}
public SimpleBean getSimpleBean() {
return simpleBean;
}
}
- For setter injection there is also a namespace to simplify the syntax with the
p-namespace
- Normally setter injection is used when the properties are not required when the bean is instanciated
- Spring allows to inject other kind of datatype, and it'll perform the conversion to the expected type. For Instance, it can convert a String
"true"
into a boolean value. For the primitive types, Spring includes their conversion types. - Spring is also able to convert data type using the "/" pattern.
- In order to support any other type, Spring provides the property editor which define the conversion between String and any other Object in order to be used in property or constructor injection.
- In order to parse correctly the date we have to do the following:
- Define a class that implements
org.springframework.beans.PropertyEditorRegistrar
which perform the conversion
package com.ps.beans.others;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateConverter implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), false));
}
}
- Add a bean definition for the
org.springframework.beans.factory.config.CustomEditorConfigurer
and provide as parameter for itsproperttyEditorRegistrars
property a list containing a bean of type DataConverter:
<beans ...>
<bean id="formatter" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd" />
</bean>
<bean id="person" class="com.ps.beans.PersonBean">
<property name="fullName" value="John Mayer"/>
<property name="birthDay">
<bean factory-bean="formatter" factory-method="parse">
<constructor-arg value="1977-10-16" />
</bean>
</property>
</bean>
</beans>
- Other type of object commonly used is collections, and it is very easy to work with them using the
<list>
element - The following example shows how to use lists:
public class CollectionHolder {
private List<SimpleBean> simpleBeanList;
public void setSimpleBeanList(List<SimpleBean> simpleBeanList) {
this.simpleBeanList = simpleBeanList;
}
- From the xml configuration file the initialization is implemented in the following way:
bean id="simpleBean" class="com.ps.beans.SimpleBeanImpl"/>
<bean id="collectionHolder" class="com.ps.beans.others.CollectionHolder">
<property name="simpleBeanList">
<list>
<ref bean="simpleBean"/>
<bean class="com.ps.beans.SimpleBeanImpl"/>
<null/>
</list>
</property>
</bean>
- In this particular case the list created with three elements. An existing instance of simpleBean, a new instance of simpleBean and a null element
- The same concept with the list can be applied to Maps and Sets:
<map>
<entry key="one" value-ref="simpleBean"/>
</map>
- Without the use of util namespace, collections can only be defined inside a bean definition. In order to define it outside a bean and give them an Id, you have to use the util namespace:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
“<bean id="simpleBean" class="com.ps.beans.SimpleBeanImpl"/>
<util:list id="simpleList">
<ref bean="simpleBean"/>
<bean class="com.ps.beans.SimpleBeanImpl"/>
<null/>
</util:list>
<util:set id="simpleSet">
<ref bean="simpleBean"/>
</util:set>
<util:map id="simpleMap">
<entry key="one" value-ref="simpleBean"/>
</util:map>
<bean id="collectionHolder" class="com.ps.beans.others.CollectionHolder">
<property name="simpleBeanList" ref="simpleList"/>
<property name="simpleBeanSet" ref="simpleSet"/>
<property name="simpleBeanMap" ref="simpleMap"/>
</bean>
<bean id="collectionHolder2" class="com.ps.beans.others.CollectionHolder">
<property name="simpleBeanList" ref="simpleList"/>
</bean>
</beans>