- <beans></beans>
<beans>作为所有<bean>的“统帅”,它拥有相应的属性(attribute)对所辖的<bean>进行统一的默认行为设置,包括如下几个
default-lazy-init (false|true): 默认为false,用来标志是否对所有的bean进行延迟初始化。
default-autowire (no|byName|byType|constructor|autodetect): 默认为no,用来标志全体bean使用哪一种默认绑定方式。
default-dependency-check(none|objects|simple|all) : 默认为none,标志全体bean做不做依赖检查。
default-init-method : 如果所管辖的bean按照某种规则,都有同样名称的初始化方法的话,可以在这里统一制定这个初始化方法名,而不用在每个bean上都重复单独指定。
default-destroy-method: 同上,指定对象销毁的方法。
2. <bean></bean>
<bean id="djNewsListener" class="..impl.DowJonesNewsListener"> </bean>
id属性:每个注册到容器的对象都需要一个唯一标志来将其与其他bean区别开来。
class属性:每个注册到容器的对象都需要class属性指定其类型,否则,容器不知道这个对象到底是什么。
3. XML 如何表达对象间的依赖性
a. 构造方法注入的XML
<bean id="djNewsProvider" class="..FXNewsProvider"> <constructor-arg ref="djNewsListener"/> <constructor-arg ref="djNewsPersister"/> </bean>
假设对象存在多个构造方法,当参数列表树木相同而类型不同的时候,容器无法区分应该使用哪个构造方法来实例化对象,或者构造方法可能同时传入最少两个类型相同的对象,这就需要type属性和index属性了。
i. type属性
public class MockBusinessObject {
private String dependency1;
private int dependency2;
public MockBusinessObject(String dependency) {
this.dependency1 = dependency;
}
public MockBusinessObject(int dependency) {
this.dependency2 = dependency;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("dependency1", dependency1)
.append("dependency2", dependency2).toString();
}
}
<bean id="mockBO" class="..MockBusinessObject"> <constructor-arg type="int"> <value>111111</value> </constructor-arg> </bean>
如果不加type="int", 默认调用第一个传入string参数的构造函数,为了指定调用第二个构造函数,需要指定type=int
ii. index属性
public class MockBusinessObject {
private String dependency1;
private String dependency2;
public MockBusinessObject(String dependency1,String dependency2){
this.dependency1 = dependency1;
this.dependency2 = dependency2;
}
@Override
public String toString() {
return new ToStringBuilder(this) ➥
.append("dependency1", dependency1) ➥
.append("dependency2", dependency2).toString();
}
}
<bean id="mockBO" class="..MockBusinessObject"> <constructor-arg index="1" value="11111"/> <constructor-arg index="0" value="22222"/> </bean>
这样可以指定11111对应第二个构造函数参数,22222对应第一个。
b. setter方法注入的XML
Spring为setter方法注入提供了<property>属性,它有一个name属性,用来指定该<property>将会注入的对象所对性的实例变量名称,之后通过value或ref属性或者内嵌的其他元素来指定具体的依赖对象饮用或者值。
<bean id="djNewsProvider" class="..FXNewsProvider"> <property name="newsListener"> <ref bean="djNewsListener"/> </property> <property name="newPersistener"> <ref bean="djNewsPersister"/> </property> </bean>
为了能够指定多种注入方式,Spring提供了其他元素来指定注入对象,包括bean/ref/idref/value/null/list/set/map/props
c. <property>和<constructor-arg>中可用的配置项
i. value
可以通过value为主体对象注入简单的数据类型。
<constructor-arg value="111111"/> <property name="attributeName" value="222222"/>
ii. ref
使用ref来引用容器中的其他的对象实例。
<constructor-arg> <ref bean="djNewsPersister"/> </constructor-arg>
iii idref
如果要为当前对象注入所依赖的对象的名称,而不是引用,就要使用idref
<property name="newsListenerBeanName"> <idref bean="djNewsListener"/> </property>
iv 内部<bean>
如果某个对象实例只有当前对象引用,其他对象无法取得该对象的引用,那么可以使用内嵌的bean,将这个私有对象定义仅局限在当前对象。
<bean id="djNewsProvider" class="..FXNewsProvider"> <constructor-arg index="0"> <bean class="..impl.DowJonesNewsListener"> </bean> </constructor-arg> <constructor-arg index="1"> <ref bean="djNewsPersister"/> </constructor-arg> </bean>
v list
<list>对应注入对象为List或其子雷或者数组类型的依赖对象,通过list可以有序地为当前对象注入以collection形式声明的依赖。
public class MockDemoObject
{
private List param1;
private String[] param2;
...
// 相应的setter和getter方法
...
}
配置类似于
<property name="param1">
<list>
<value> something</value>
<ref bean="someBeanName"/>
<bean class="..."/>
</list>
</property>
<property name="param2">
<list>
<value>stringValue1</value>
<value>stringValue2</value>
</list>
</property>
vi set
set是无序的
public class MockDemoObject
{
private Set valueSet;
// 必要的setter和getter方法
...
}
配置类似于
<property name="valueSet">
<set>
<value> something</value>
<ref bean="someBeanName"/>
<bean class="..."/>
<list>
...
</list>
</set>
</property>
vii map
map可以通过指定的key来获取相应的值
public class MockDemoObject
{
private Map mapping;
// 必要的setter和getter方法
...
}
配置类似于
<property name="mapping">
<map>
<entry key="strValueKey">
<value>something</value>
</entry>
<entry>
<key>objectKey</key>
<ref bean="someObject"/>
</entry>
<entry key-ref="lstKey">
<list>
...
</list>
</entry>
...
</map>
< /property>
viii props
<props>是简化后了的<map>,或者说是特殊化的map,该元素对应配置类型为java.util.Properties的对象依赖。因为Properties只能指定String类型的键(key)和值,所以,<props>的配置简化很多,只有固定的格式.
public class MockDemoObject
{
private Properties emailAddrs;
// 必要的setter和getter方法
...
}
配置类似于
<property name="valueSet">
<props>
<prop key="author">fujohnwang@gmail.com</prop>
<prop key="support">support@spring21.cn</prop>
...
</props>
</property>
viiii <null/>
它只是一个空元素,而且通常使用到它的场景也不是很多。对于String类型来说,如果通过value以这样的方式指定注入,即<value></value>,那么,得到的结果是"",而不是null。所以,如果需要为这个string对应的值注入null的话,请使用<null/>
d. depends-on
如果某些时候没有通过类似<ref>的元素明确指定对象A依赖于对象B的话,可以使用depends-on属性来指定非显式依赖关系。
<bean id="classAInstance" class="...ClassA" depends- on="configSetup,configSetup2,..."/> <bean id="configSetup" class="SystemConfigurationSetup"/> <bean id="configSetup2" class="SystemConfigurationSetup2"/>
e. autowire
Spring提供了5种自动绑定模式,即no, byName, byType, constructor 和autodetect
i. byName
按照类中声明的实例变量的名称,与XML配置文件中声明的beanName的值进行匹配,相匹配的bean定义将自动绑定到当前实例变量上。
public class Foo
{
private Bar emphasisAttribute;
...
// 相应的setter方法定义
}
public class Bar
{
...
}
<bean id="fooBean" class="...Foo" autowire="byName">
</bean>
<bean id="emphasisAttribute" class="...Bar">
</bean>
ii. byType
如果指定当前bean定义的autowire模式为byType,那么容器会根据当前bean定义类型,分析其相应的依赖对象类型,然后到容器所管理的所有bean定义中寻找与依赖对象类型相同的bean定义,然后将找到符合条件的bean自动绑定到当前bean定义。byType只能保证,在容器中只存在一个符合条件的以来对象的时候才会发挥最大的作用,如果容器中存在多个相同类型的bean定义,那么就需要手动明确配置。
<bean id="fooBean" class="...Foo" autowire="byType"> </bean> <bean id="anyName" class="...Bar"> < /bean>
iii. constructor
byName和byType类型的自动绑定模式是针对property的自动绑定,而constructor类型则是针对构造方法参数的类型而进行的自动绑定,它同样是byType类型的绑定模式。不过,constructor是匹配构造方法的参数类型,而不是实例属性的类型。与byType模式类似,如果找到不止一个符合条件的bean定义,那么,容器会返回错误。
public class Foo {
private Bar bar;
public Foo(Bar arg) {
this.bar = arg;
}
...
}
// 相应配置如下
<bean id="foo" class="...Foo" autowire="constructor"/>
<bean id="bar" class="...Bar"> < /bean>
iv. autodetect
这种模式是byType和constructor模式的结合体,如果对象拥有默认无参数的构造方法,容器会优先考虑byType的自动绑定模式。否则,会使用constructor模式。当然,如果通过构造方法注入绑定后还有其他属性没有绑定,容器也会使用byType对剩余的对象属性进行自动绑定。
- 使用继承关系配置
<bean id="superNewsProvider" class="..FXNewsProvider"> <property name="newsListener"> <ref bean="djNewsListener"/> </property> <property name="newPersistener"> <ref bean="djNewsPersister"/> </property> </bean> <bean id="subNewsProvider" parent="superNewsProvider" class="..SpecificFXNewsProvider"> <property name="newsListener"> <ref bean="specificNewsListener"/> </property> </bean>
我们在声明subNewsProvider的时候,使用了parent属性,将其值指定为superNewsProvider,这样就继承了superNewsProvider定义的默认值,只需要将特定的属性进行更改,而不要全部又重新定义一遍。
parent属性还可以与abstract属性结合使用,达到将相应bean定义模板化的目的。
<bean id="newsProviderTemplate" abstract="true"> <property name="newPersistener"> <ref bean="djNewsPersister"/> </property> </bean> <bean id="superNewsProvider" parent="newsProviderTemplate" class="..FXNewsProvider"> <property name="newsListener"> <ref bean="djNewsListener"/> </property> </bean> <bean id="subNewsProvider" parent="newsProviderTemplate" class="..SpecificFXNewsProvider"> <property name="newsListener"> <ref bean="specificNewsListener"/> </property> </bean>
newsProviderTemplate的bean定义通过abstract属性声明为true,说明这个bean定义不需要实例化。该bean定义只是一个配置模板,不对应任何对象。superNews-Provider和subNewsProvider通过parent指向这个模板定义,就拥有了该模板定义的所有属性配置。