From book Spring Recipes. Most basic Spring application: starts with simple beans, then adds lists as properties of the bean. Ingredients: 1. JDK 1.6
2. Simplest version of Eclipse IDE for Java Develpoment
3. spring-framework-3.1.0.M1.zip Make a Java project in eclipse. make a folder in the root of the project Unzip spring-framework-3.1.0.M1.zip from ./dist/ directory you will need
org.springframework.asm-3.1.0.M1.jar
org.springframework.beans-3.1.0.M1.jar org.springframework.context-3.1.0.M1.jar org.springframework.core-3.1.0.M1.jar org.springframework.expression-3.1.0.M1.jar from ./projects/spring-build/lib/ivy/
commons-logging.jar
Make a bean class
package com.apress.springrecipes.sequence;
public class SequenceGenerator { private String prefix; private String suffix; private int initial; private int counter; public SequenceGenerator() {} public SequenceGenerator(String prefix, String suffix, int initial) { this.prefix = prefix; this.suffix = suffix; this.initial = initial; } public void setPrefix(String prefix) { this.prefix = prefix; } public void setSuffix(String suffix) { this.suffix = suffix; } public void setInitial(int initial) { this.initial = initial; } public synchronized String getSequence() { StringBuffer buffer = new StringBuffer(); buffer.append(prefix); buffer.append(initial + counter++); buffer.append(suffix); return buffer.toString(); } } Make a beans.xml file in the ./src/ directory of the project: <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 name="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator"> <property name="prefix"> <value>30</value> </property> <property name="suffix"> <value>A</value> </property> <property name="initial"> <value>100000</value> </property> </bean> </beans> Make a runner class to test if this spring project works. import org.springframework.context.ApplicationContext;
Run it, output:import org.springframework.context.support.ClassPathXmlApplicationContext; import com.apress.springrecipes.sequence.SequenceGenerator; public class runner { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); SequenceGenerator generator = (SequenceGenerator) context.getBean("sequenceGenerator"); System.out.println(generator.getSequence()); System.out.println(generator.getSequence()); } } Mar 29, 2011 11:19:24 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@145d068: startup date [Tue Mar 29 11:19:24 CDT 2011]; root of context hierarchy Mar 29, 2011 11:19:24 AM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [beans.xml] Mar 29, 2011 11:19:25 AM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@ce5b1c: defining beans [sequenceGenerator]; root of factory hierarchy 30100000A 30100001A ---------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------- You could also get the bean via constructor arguments <bean name="sequenceGenerator"
----------------------------------------------------------------------------------------------------------------------------------------class="com.apress.springrecipes.sequence.SequenceGenerator"> <constructor-arg> <value>30</value> </constructor-arg> <constructor-arg> <value>A</value> </constructor-arg> <constructor-arg> <value>100000</value> </constructor-arg> </bean> ---------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------- You could also declare the bean using a shortcut format using the value attribute <bean id="sequenceGenerator"
The same way for the constructor argumentsclass="com.apress.springrecipes.sequence.SequenceGenerator"> <property name="prefix" value="30" /> <property name="suffix" value="A" /> <property name="initial" value="100000" /> </bean> <bean name="sequenceGenerator"
----------------------------------------------------------------------------------------------------------------------------------------class="com.apress.springrecipes.sequence.SequenceGenerator"> <constructor-arg value="30" /> <constructor-arg value="A" /> <constructor-arg value="100000" /> </bean> ---------------------------------------------------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------- You could also declare the bean using attribute names for each field of the bean. <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/spring-beans-3.0.xsd"> <bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator" p:prefix="30" p:suffix="A" p:initial="100000" /> </beans> Add CollectionsList(Array), SetThe elements allowed inside the <list> tag can be a simple constant value specified by <value>, a bean reference by <ref>, an inner bean definition by <bean>, an ID reference definition by <idref>, or a null element by <null>. You can even embed other collections in a
collection. Modify the bean class to include a list (of suffices) package com.apress.springrecipes.sequence;
import java.util.List; public class SequenceGenerator { private String prefix; private List<Object> suffixes; private int initial; private int counter; public SequenceGenerator() { } public SequenceGenerator(String prefix, List<Object> suffixes, int initial) { this.prefix = "MMM"; this.suffixes = suffixes; this.initial = initial; } public void setPrefix(String prefix) { this.prefix = prefix; } public void setSuffixes(List<Object> suffixes) { this.suffixes = suffixes; } public void setInitial(int initial) { this.initial = initial; } public synchronized String getSequence() { StringBuffer buffer = new StringBuffer(); buffer.append(prefix); buffer.append(initial + counter++); for (Object suffix : suffixes) { buffer.append("-"); buffer.append(suffix); } return buffer.toString(); } } Modify the bean.xml <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 name="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator"> <property name="prefix"> <value>30</value> </property> <property name="suffixes"> <list> <value>A</value> <bean class="java.net.URL"> //relates to the constructor of the URL(protocol, host,file) <constructor-arg value="http" /> <constructor-arg value="www.apress.com" /> <constructor-arg value="/" /> </bean> <null /> </list> </property> <property name="initial"> <value>100000</value> </property> </bean> </beans> If suffixes was an array of Objects instead: The definition of an array in the bean configuration file is identical to a list denoted by the <list> tag. If suffixes was a set of Objects instead: The definition of an array in the bean configuration file should be declared using the <set> tag. Spring preserves the order of your elements by using java.util.LinkedHashSet, Output is Mar 29, 2011 1:10:36 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@145d068: startup date [Tue Mar 29 13:10:36 CDT 2011]; root of context hierarchy Mar 29, 2011 1:10:36 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [beans.xml] Mar 29, 2011 1:10:37 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1e8a1f6: defining beans [sequenceGenerator]; root of factory hierarchy 30100000-A-http://www.apress.com/-null 30100001-A-http://www.apress.com/-null package com.apress.springrecipes.sequence;
... public class SequenceGenerator { ... private Map<Object, Object> suffixes; public void setSuffixes(Map<Object, Object> suffixes) { this.suffixes = suffixes; } public synchronized String getSequence() { StringBuffer buffer = new StringBuffer(); ... for (Map.Entry entry : suffixes.entrySet()) { buffer.append("-"); buffer.append(entry.getKey()); buffer.append("@"); buffer.append(entry.getValue()); } return buffer.toString(); } } bean.xml
<bean id="sequenceGenerator"
class="com.apress.springrecipes.sequence.SequenceGenerator"> ... <property name="suffixes"> <map> <entry key="type" value="A" /> <entry key="url"> <bean class="java.net.URL"> <constructor-arg value="http" /> <constructor-arg value="www.apress.com" /> <constructor-arg value="/" /> </bean> </entry> </map> </property> </bean> Output: Mar 29, 2011 1:45:45 PM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@145d068: startup date [Tue Mar 29 13:45:45 CDT 2011]; root of context hierarchy Mar 29, 2011 1:45:45 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions INFO: Loading XML bean definitions from class path resource [beans.xml] Mar 29, 2011 1:45:45 PM org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@a3d4cf: defining beans [sequenceGenerator]; root of factory hierarchy 30100000-type@A-url@http://www.apress.com/ 30100001-type@A-url@http://www.apress.com/ Nulled map value <property name="nulledMapValue">
<map> <entry> <key> <value>null</value> </key> </entry> </map> </property> Properties : Maps that are always Strings
private Properties suffixes;
public void setSuffixes(Properties suffixes) { this.suffixes = suffixes; } <props> <prop key="type">A</prop> <prop key="url">http://www.apress.com/</prop> <prop key="null">null</prop> </props> Declare Inheritance in bean.xml
bean.xml <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 id="baseSequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator"> <property name="prefix" value="30" /> <property name="initial" value="100000" /> <property name="suffixes"> <list> <value>A</value> <value>B</value> </list> </property> </bean> <bean id="sequenceGenerator" parent="baseSequenceGenerator"> <property name="prefix" value="PRE" /> <property name="suffixes"> <list merge="true"> <value>A</value> <value>C</value> </list> </property> </bean> </beans> Simple list-based sequence generator:
package com.apress.springrecipes.sequence; import java.util.List; public class SequenceGenerator { private String prefix; private List<Object> suffixes; private int initial; private int counter; public void setPrefix(String prefix) { this.prefix = prefix; } public void setSuffixes(List<Object> suffixes) { this.suffixes = suffixes; } public void setInitial(int initial) { this.initial = initial; } public synchronized String getSequence() { StringBuffer buffer = new StringBuffer(); buffer.append(prefix); buffer.append(initial + counter++); for (Object suffix : suffixes) { buffer.append("-"); buffer.append(suffix); } return buffer.toString(); } } Output 30100000-A-B-A-C 30100001-A-B-A-C Note: 1. The attributes of the parent will be inherited at the child, If they are not declared at the child (PRE has been over-written by the child) 2. Note that the bean class itself does not declare any inheritance 3. The content of the list will be appended (if it is a set instead, redundancies will be eliminated) Object InstantiationIf there’s no <constructor-arg> element specified, the default constructor with no argument will be invoked. Then for each <property> element, Spring will inject the value through the setter method. Otherwise, if there are one or more <constructor-arg> elements specified, Spring will invoke the most appropriate constructor that matches your arguments. <bean id="aaa" class="com.apress.springrecipes.shop.Battery"> <constructor-arg value="AAA" /> <constructor-arg value="2.5" /> <property name="rechargeable" value="true" /> </bean> Equivalent to Product aaa = new Battery("AAA", 2.5); aaa.setRechargeable(true); To avoid ambiguity over which constructor you intended to execute, use the optional attributes type and index for the <constructor-arg>. There’s not a name attribute in <constructor-arg>, as constructor arguments are position-based.(at runtime there is no parameter name over method calls.) <constructor-arg type="int" index="0" value="100000" /> <constructor-arg type="java.lang.String" index="1" value="A" /> Bean Reference DeclarationExample: In case of the sequence number generator example, here we avoid using String as prefix and use an interface as a prefix generator: package com.apress.springrecipes.sequence; public interface PrefixGenerator { public String getPrefix(); } Assume we use current date as the prefix generated: package com.apress.springrecipes.sequence; public class DatePrefixGenerator implements PrefixGenerator { private DateFormat formatter; public void setPattern(String pattern) { this.formatter = new SimpleDateFormat(pattern); } public String getPrefix() { return formatter.format(new Date()); } } Specify a bean reference for a bean property or a constructor argument 1. by the <ref> element. bean.xml would have: <bean id="datePrefixGenerator" class="com.apress.springrecipes.sequence.DatePrefixGenerator"> <property name="pattern" value="yyyyMMdd" /> </bean> <bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator"> <property name="initial" value="100000" /> <property name="suffix" value="A" /> <property name="prefixGenerator"> <ref bean="datePrefixGenerator" /> </property> </bean> The
bean name in the <ref> element’s bean attribute can be a
reference to any bean in the IoC container, even if it’s not defined in
the same XML configuration file. If you are referring to a bean in the
same XML file, you should use the local attribute, as it is an XML ID reference. so:
OR <property name="prefixGenerator" ref="datePrefixGenerator" /> Benefit of local: XML editors can be used to check the integrity (e.g. eclipse right click the XML document->Validate) OR <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/spring-beans-3.0.xsd"> <bean id="sequenceGenerator" class="com.apress.springrecipes.sequence.SequenceGenerator" p:suffix="A" p:initial="1000000" p:prefixGenerator-ref="datePrefixGenerator" /> //suffix with ref </beans> 2. Enclose a bean declaration as an inner bean inside the tag you need it. <property name="prefixGenerator"> //or it could be <constructor-arg> <bean class="com.apress.springrecipes.sequence.DatePrefixGenerator"> <property name="pattern" value="yyyyMMdd" /> </bean> </property> Typetype attribute of single entities OR value-type attribute of the collection tag to specify the type for all elements in this collection OR defined your collections in a type-safe way private List<Integer> suffixes;Spring will convert data from XML file itself to integers.
then suffixes in the example could be private List<Object> suffixes; |