Configuring Beans in the Spring IoC Container
这本书对spring bean的配置比较全面。
注:配置类似
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
的时候,xsd的版本号不要带,至于为什么,参考以前转载的老外博客。
Problem
Spring offers a powerful IoC container to manage the beans that make up an application. To utilize the
container services, you have to configure your beans to run in the Spring IoC container.
Solution
You can configure your beans in the Spring IoC container through XML files, properties files,
annotations, or even APIs.
Spring allows you to configure your beans in one or more bean configuration files. For a
simple application, you can simply centralize your beans in a single configuration file. But for a large
application with a lot of beans, you should separate them in multiple configuration files according to
their functionalities. One useful division is by the architectural layer that a given context services.
How It Works
Suppose that you are going to develop an application for generating sequence numbers. In this
application, there may be many series of sequence numbers to generate for different purposes. Each
one of them will have its own prefix, suffix, and initial value. So, you have to create and maintain
multiple generator instances in your application.
Creating the Bean Class
In accordance with the requirements, you create the SequenceGenerator class that has three
properties_prefix, suffix, and initial_that can be injected via setter methods or a constructor. The
private field counter is for storing the current numeric value of this generator. Each time you call the
getSequence() method on a generator instance, you will get the last sequence number with the prefix
and suffix joined. You declare this method as synchronized to make it thread-safe.
package com.apress.springenterpriserecipes.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(); } }
As you see, this SequenceGenerator class can be configured by getters/setters or by the constructor.
When configuring them with the container, this is called constructor injection and setter injection.
Creating the Bean Configuration File
To declare beans in the Spring IoC container via XML, you first have to create an XML bean
configuration file with an appropriate name, such as beans.xml. You can put this file in the root
of the classpath for easier testing within an IDE.
The Spring configuration XML allows you to use custom tags from different schemas (tx, jndi, jee,
and so on) to make the bean configuration simpler and clearer. Here’s an example of the simplest XML
configuration possible.
<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>
Declaring Beans in the Bean Configuration File
Each bean should provide a unique name or id and a fully qualified class name for the Spring IoC
container to instantiate it. For each bean property of simple type (e.g., String and other primitive types),
you can specify a <value> element for it. Spring will attempt to convert your value into the declaring type
of this property. To configure a property via setter injection, you use the <property> element and specify
the property name in its name attribute. A <property> requires that the bean contain a corresponding
setter method.
<bean name="sequenceGenerator" class="com.apress.springenterpriserecipes.sequence.SequenceGenerator"> <property name="prefix"> <value>30</value> </property> <property name="suffix"> <value>A</value> </property> <property name="initial"> <value>100000</value> </property> </bean>
You can also configure bean properties via constructor injection by declaring them in the
<constructor-arg>
elements. There’s not a
name
attribute in
<constructor-arg>
because constructor
arguments are position-based.
<bean name="sequenceGenerator" class="com.apress.springenterpriserecipes.sequence.SequenceGenerator"> <constructor-arg> <value>30</value> </constructor-arg> <constructor-arg> <value>A</value> </constructor-arg> <constructor-arg> <value>100000</value> </constructor-arg> </bean>
In the Spring IoC container, each bean’s name should be unique, although duplicate names are
allowed for overriding bean declaration if more than one context is loaded. A bean’s name can be
defined by the name
attribute of the <bean>
element. Actually, there’s a preferred way of identifying a
bean: through the standard XML
id attribute, whose purpose is to identify an element within an XML
document. In this way, if your text editor is XML-aware, it can help to validate each bean’s uniqueness at
design time.
<bean id="sequenceGenerator" class="com.apress.springenterpriserecipes.sequence.SequenceGenerator"> ... </bean>
However, XML has restrictions on the characters that can appear in the XML
id
attribute, but
usually you won’t use those special characters in a bean name. Moreover, Spring allows you to specify
multiple names, separated by commas, for a bean in the
name attribute. But you can’t do so in the
id
attribute because commas are not allowed there.
In fact, neither the bean name nor the bean ID is required for a bean. A bean that has no name
defined is called an anonymous bean. You will usually create beans like this that serve only to interact
with the Spring container itself; that you are sure you will only inject by type later on; or that you will
nest, inline, in the declaration of an outer bean.
Defining
Bean Properties by Shortcut
Spring
supports a shortcut for specifying the value of a simple type property. You can present a
value
attribute in the
<property> element instead of enclosing a
<value>
element inside.
<bean id="sequenceGenerator" class="com.apress.springenterpriserecipes.sequence.SequenceGenerator"> <property name="prefix" value="30" /> <property name="suffix" value="A" /> <property name="initial" value="100000" /> </bean> This shortcut also works for constructor arguments. <bean name="sequenceGenerator" class="com.apress.springenterpriserecipes.sequence.SequenceGenerator"> <constructor-arg value="30" /> <constructor-arg value="A" /> <constructor-arg value="100000" /> </bean>
Spring 2.0 provides another convenient shortcut for you to define properties. It’s by using the
p
schema to define bean properties as attributes of the
<bean>
element. This can shorten the lines of XML
configuration.
<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">
<span style="font-family: TheSansMonoCondensed-Plain; font-size: 9pt;"><bean id="sequenceGenerator" <span style="font-size: 9pt;">class="com.apress.springenterpriserecipes.sequence.SequenceGenerator" <span style="font-family: TheSansMonoCondensed-Black; font-size: 9pt;">p:prefix="30" p:suffix="A" p:initial="100000" /> <span style="font-family: TheSansMonoCondensed-Plain; font-size: 9pt;"></beans></span></span></span><br style="orphans: 2; text-align: -webkit-auto; widows: 2;" /></span>
Configuring Collections for Your Beans
List,
Set, and
Map
are the core interfaces representing three main types of collections. For each
collection type, Java provides several implementations with different functions and characteristics from
which you can choose. In Spring, these types of collections can be easily configured with a group of
built-in XML tags, such as <list>,
<set>, and
<map>.
Suppose you are going to allow more than one suffix for your sequence generator. The suffixes will
be appended to the sequence numbers with hyphens as the separators. You may consider accepting
suffixes of arbitrary data types and converting them into strings when appending to the sequence
numbers.
Lists, Arrays, and Sets
First, let’s use a java.util.List
collection to contain your suffixes. A
list is an ordered and indexed
collection whose elements can be accessed either by index or with a for-each loop.
package com.apress.springenterpriserecipes.sequence; ... public class SequenceGenerator { ... private List<Object> suffixes; public void setSuffixes(List<Object> suffixes) { this.suffixes = suffixes; } public void setPrefixGenerator(PrefixGenerator prefixGenerator) { this.prefixGenerator = prefixGenerator; } public synchronized String getSequence() { StringBuffer buffer = new StringBuffer(); ... for (Object suffix : suffixes) { buffer.append("-"); buffer.append(suffix); } return buffer.toString(); } }
To define a property of the interface
java.util.List
in the bean configuration, you specify a
<list>
tag that contains the elements. The 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>, or a null
element by <null>. You can even embed other collections in a collection.
<bean id="sequenceGenerator" class="com.apress.springenterpriserecipes.sequence.SequenceGenerator"> <property name="prefixGenerator" ref="datePrefixGenerator" /> <property name="initial" value="100000" /> <property name="suffixes"> <list> <value>A</value> <bean class="java.net.URL"> <constructor-arg value="http" /> <constructor-arg value="www.apress.com" /> <constructor-arg value="/" /> </bean> <null /> </list> </property> </bean>
Conceptually, an
array is very similar to a list in that it’s also an ordered and indexed collection that
can be accessed by index. The main difference is that the length of an array is fixed and cannot be
extended dynamically. In the Java Collections framework, an array and a list can be converted to each
other through the Arrays.asList()
and
List.toArray() methods. For your sequence generator, you can
use an Object[]
array to contain the suffixes and access them either by index or with a for-each loop.
package com.apress.springenterpriserecipes.sequence; ... public class SequenceGenerator { ... private Object[] suffixes; public void setSuffixes(Object[] suffixes) { this.suffixes = suffixes; } ... }
The definition of an array in the bean configuration file is identical to a list denoted by the
<list>
tag.
Another common collection type is a set. Both the
java.util.List
interface and the java.util.Set
interface extend the same interface:
java.util.Collection. A set differs from a list in that it is neither
ordered nor indexed, and it can store unique objects only. That means no duplicate element can be
contained in a set. When the same element is added to a set for the second time, it will replace the old
one. The equality of elements is determined by the
equals() method.
package com.apress.springenterpriserecipes.sequence;
package com.apress.springenterpriserecipes.sequence; ... public class SequenceGenerator { ... private Set<Object> suffixes; public void setSuffixes(Set<Object> suffixes) { this.suffixes = suffixes; } ... }
To define a property of
java.util.Set
type, use the
<set>
tag to define the elements in the same way
as a list.
<bean id="sequenceGenerator" class="com.apress.springenterpriserecipes.sequence.SequenceGenerator"> ... <property name="suffixes"> <set> <value>A</value> <bean class="java.net.URL"> <constructor-arg value="http" /> <constructor-arg value="www.apress.com" /> <constructor-arg value="/" /> </bean> <null /> </set> </property> </bean>
Although there’s not an order concept in the original set semantics, Spring preserves the order of
your elements by using java.util.LinkedHashSet, an implementation of the
java.util.Set
interface
that does preserve element order.
Maps
and Properties
A
map
is a table that stores its entries in key/value pairs. You can get a particular value from a map by its
key, and also iterate the map entries with a for-each loop. Both the keys and values of a map can be of
arbitrary type. Equality between keys is also determined by the
equals() method. For example, you can
modify your sequence generator to accept a
java.util.Map collection that contains suffixes with keys.
package com.apress.springenterpriserecipes.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(); } }
In Spring, a map is defined by the
<map>
tag, with multiple
<entry>
tags as children. Each entry
contains a key and a value. The key must be defined inside the <key>
tag. There is no restriction on the
type of the key and value, so you are free to specify a <value>,
<ref>,
<bean>,
<idref>, or
<null>
element
for them. Spring will also preserve the order of the map entries by using
java.util.LinkedHashMap.
<bean id="sequenceGenerator" class="com.apress.springenterpriserecipes.sequence.SequenceGenerator"> ... <property name="suffixes"> <map> <entry> <key> <value>type</value> </key> <value>A</value> </entry> <entry> <key> <value>url</value> </key> <bean class="java.net.URL"> <constructor-arg value="http" /> <constructor-arg value="www.apress.com" /> <constructor-arg value="/" /> </bean> </entry> </map> </property> </bean>
There are shortcuts to defining map keys and values as attributes of the
<entry>
tag. If they are
simple constant values, you can define them by key
and
value. If they are bean references, you can
define them by key-ref
and
value-ref.
<pre name="code" class="html"><bean id="sequenceGenerator" class="com.apress.springenterpriserecipes.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>
In all the collection classes seen thus far, you used values to set the properties. Sometimes the
desired goal is to configure a
null value using a
Map instance. Spring’s XML configuration schema
includes explicit support for this. Here is a map with null values for the value of an entry:
<property name="nulledMapValue"> <map> <entry> <key> <value>null</value> </key> </entry> </map> </property>
A
java.util.Properties collection is very similar to a map. It also implements the
java.util.Map
interface and stores entries in key/value pairs. The only difference is that the keys and values of a
Properties
collection are always strings.
package com.apress.springenterpriserecipes.sequence; ... public class SequenceGenerator { ... private Properties suffixes; public void setSuffixes(Properties suffixes) { this.suffixes = suffixes; } ... }
To define a
java.util.Properties collection in Spring, use the
<props>
tag with multiple <prop>
tags
as children. Each <prop>
tag must have a key
attribute defined and the corresponding value enclosed.
<bean id="sequenceGenerator" class="com.apress.springenterpriserecipes.sequence.SequenceGenerator"> ... <property name="suffixes"> <props> <prop key="type">A</prop> <prop key="url">http://www.apress.com/</prop> <prop key="null">null</prop> </props> </property> </bean>
If you define your beans with inheritance, a child bean’s collection can be merged with that of its
parent by setting the merge
attribute to
true. For a
<list>
collection, the child elements will be added.
来源:
Spring Enterprise Recipes: A Problem-Solution Approach 2016年2月10
Copyright ? 2009 by Gary Mak and Josh Long
All rights reserved. No part of this work may be reproduced or transmitted in any form or by any
means, electronic or mechanical, including photocopying, recording, or by any information
storage or retrieval system, without the prior written permission of the copyright owner and the
publisher.
ISBN-13 (pbk): 978-1-4302-2497-6
ISBN-13 (electronic): 978-1-4302-2498-3
Printed and bound in the United States of America 9 8 7 6 5 4 3 2 1