[b]3.3. 依赖[/b]
[b]3.3.1. 注入依赖[/b]
DI主要有两种注入方式,即Setter注入和 构造器注入
[b]3.3.1.1. Setter注入[/b]
通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即可实现基于setter的DI
[b]3.3.1.2. 构造器注入[/b]
[b]3.3.1.3. 一些例子[/b]
[b]示例一:[/b]
[b]示例二:[/b]
示例三:采用静态工厂方法取代构造方法
[b]3.3.2. 构造器参数的解析[/b]
构造器参数将根据类型来进行匹配。如果bean定义中的构造器参数类型明确,那么bean定义中的参数顺序就是对应构造器参数的顺序。
当引用的bean类型已知,则匹配没有问题(如上述的例子)。但是当使用象<value>true<value>这样的简单类型时,Spring将无法决定该值的类型,因而仅仅根据类型是无法进行匹配的。
[b]3.3.2.1. 构造器参数类型匹配[/b]
[b]3.3.2.2. 构造器参数的索引[/b]
[b]3.3.3. bean属性及构造器参数详解[/b]
[b]3.3.3.1. 直接量(基本类型、Strings类型等。)[/b]
[b]3.3.3.1.1. idref元素[/b]
如果被引用的bean在同一XML文件内,且bean名字就是bean id,那么可以使用local属性,此属性允许XML解析器在解析XML文件时来对引用的bean进行验证。
[b]3.3.3.2. 引用其它的bean(协作者)[/b]
第三种方式是通过使用ref的parent属性来引用当前容器的父容器中的bean。parent属性值既可以是目标bean的id值,也可以是name属性值。而且目标bean必须在当前容器的父容器中。使用parent属性的主要用途是为了用某个与父容器中的bean同名的代理来包装父容器中的一个bean(例如,子上下文中的一个bean定义覆盖了他的父bean)。
[b]3.3.3.4. 集合[/b]
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@somecompany.org</prop>
<prop key="support">support@somecompany.org</prop>
<prop key="development">development@somecompany.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry>
<key>
<value>yup an entry</value>
</key>
<value>just some string</value>
</entry>
<entry>
<key>
<value>yup a ref</value>
</key>
<ref bean="myDataSource" />
</entry>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
[b]</bean>[/code]
3.3.3.4.1. 集合合并[/b]
不同的集合类型是不能合并(如map和 list是不能合并的),否则将会抛出相应的Exception。merge属性必须在继承的子bean中定义,而在父bean的集合属性上指定的merge属性将被忽略。
[b]3.3.3.4.2. 强类型集合(仅适用于Java5+)[/b]
[b]3.3.3.5. Nulls[/b]
注意区别空串
[b]3.3.3.6. XML-based configuration metadata shortcuts[/b]
等同于
<property/>和<constructor-arg/>支持类似的简写属性ref,它可能用来替代整个内嵌的<ref/>元素。
等同于
map中entry元素的简写形式为key/key-ref 和 value /value-ref属性
等同于
[b]3.3.3.7. 组合属性名称[/b]
除了最后一个属性外,只要其他属性值不为null,组合或嵌套属性名是完全合法的
若需要表达对多个bean的依赖,可以在'depends-on'中将指定的多个bean名字用分隔符进行分隔,分隔符可以是逗号、空格及分号等:
[b]3.3.5. 延迟初始化bean[/b]
ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的singleton bean。
有时候这种默认处理可能并不是你想要的。如果你不想让一个singleton bean在ApplicationContext实现在初始化时被提前实例化,那么可以将bean设置为延迟实例化。一个延迟初始化bean将告诉IoC 容器是在启动时还是在第一次被用到时实例化。
需要说明的是,如果一个bean被设置为延迟初始化,而另一个非延迟初始化的singleton bean依赖于它,那么当ApplicationContext提前实例化singleton bean时,它必须也确保所有上述singleton 依赖bean也被预先初始化,当然也包括设置为延迟实例化的bean。因此,如果Ioc容器在启动的时候创建了那些设置为延迟实例化的bean的实例,你也不要觉得奇怪,因为那些延迟初始化的bean可能在配置的某个地方被注入到了一个非延迟初始化singleton bean里面。
在容器层次中通过在<beans/>元素上使用'default-lazy-init'属性来控制延迟初始化也是可能的。如下面的配置:
[b]3.3.6. 自动装配(autowire)协作者[/b]
[img]C:\Documents and Settings\Administrator\桌面\2222.bmp[/img]
[b]3.3.6.1. 设置Bean使自动装配失效[/b]
<bean/>元素的 autowire-candidate属性可被设为false,这样容器在查找自动装配对象时将不考虑该bean
[b]3.3.7. 依赖检查[/b]
dependency-check
[img]C:\Documents and Settings\Administrator\桌面\333.bmp[/img]
[b]3.3.1. 注入依赖[/b]
DI主要有两种注入方式,即Setter注入和 构造器注入
[b]3.3.1.1. Setter注入[/b]
通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即可实现基于setter的DI
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a setter method so that the Spring container can
//'inject' a MovieFinder
public void setMoveFinder(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually 'uses' the injected
//MovieFinder is omitted...
}
[b]3.3.1.2. 构造器注入[/b]
public class SimpleMovieLister {
// the SimpleMovieLister has a dependency on the MovieFinder
private MovieFinder movieFinder;
// a constructor so that the Spring container
//can 'inject' a MovieFinder
public SimpleMovieLister(MovieFinder movieFinder) {
this.movieFinder = movieFinder;
}
// business logic that actually 'uses' the injected
//MovieFinder is omitted...
}
[b]3.3.1.3. 一些例子[/b]
[b]示例一:[/b]
<bean id="exampleBean" class="examples.ExampleBean">
<!-- setter injection using the nested <ref/> element -->
<property name="beanOne">
<ref bean="anotherExampleBean"/>
</property>
<!-- setter injection using the neater 'ref' attribute -->
<property name="beanTwo" ref="yetAnotherBean"/>
<property name="integerProperty" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public void setBeanOne(AnotherBean beanOne) {
this.beanOne = beanOne;
}
public void setBeanTwo(YetAnotherBean beanTwo) {
this.beanTwo = beanTwo;
}
public void setIntegerProperty(int i) {
this.i = i;
}
}
[b]示例二:[/b]
<bean id="exampleBean" class="examples.ExampleBean">
<!-- constructor injection using the nested <ref/> element -->
<constructor-arg>
<ref bean="anotherExampleBean"/>
</constructor-arg>
<!-- constructor injection using the neater 'ref' attribute -->
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg type="int" value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
private int i;
public ExampleBean(
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
this.beanOne = anotherBean;
this.beanTwo = yetAnotherBean;
this.i = i;
}
}
示例三:采用静态工厂方法取代构造方法
<bean id="exampleBean" class="examples.ExampleBean"
factory-method="createInstance">
<constructor-arg ref="anotherExampleBean"/>
<constructor-arg ref="yetAnotherBean"/>
<constructor-arg value="1"/>
</bean>
<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {
// a private constructor
private ExampleBean(...) {
...
}
// a static factory method; the arguments to this method can be
// considered the dependencies of the bean that is returned,
// regardless of how those arguments are actually used.
public static ExampleBean createInstance (
AnotherBean anotherBean, YetAnotherBean yetAnotherBean, int i) {
ExampleBean eb = new ExampleBean (...);
// some other operations
...
return eb;
}
}
[b]3.3.2. 构造器参数的解析[/b]
构造器参数将根据类型来进行匹配。如果bean定义中的构造器参数类型明确,那么bean定义中的参数顺序就是对应构造器参数的顺序。
当引用的bean类型已知,则匹配没有问题(如上述的例子)。但是当使用象<value>true<value>这样的简单类型时,Spring将无法决定该值的类型,因而仅仅根据类型是无法进行匹配的。
package examples;
public class ExampleBean {
// No. of years to the calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
}
[b]3.3.2.1. 构造器参数类型匹配[/b]
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
[b]3.3.2.2. 构造器参数的索引[/b]
<bean id="exampleBean" class="examples.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
[b]3.3.3. bean属性及构造器参数详解[/b]
[b]3.3.3.1. 直接量(基本类型、Strings类型等。)[/b]
<bean id="myDataSource" destroy-method="close"
class="org.apache.commons.dbcp.BasicDataSource">
<!-- results in a setDriverClassName(String) call -->
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/mydb</value>
</property>
<property name="username">
<value>root</value>
</property>
</bean>
[b]3.3.3.1.1. idref元素[/b]
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean" />
</property>
</bean>
如果被引用的bean在同一XML文件内,且bean名字就是bean id,那么可以使用local属性,此属性允许XML解析器在解析XML文件时来对引用的bean进行验证。
<property name="targetName">
<!-- a bean with an id of 'theTargetBean' must exist, else an XML exception will be thrown -->
<idref local="theTargetBean"/>
</property>
[b]3.3.3.2. 引用其它的bean(协作者)[/b]
<ref bean="someBean"/>
<ref local="someBean"/>
第三种方式是通过使用ref的parent属性来引用当前容器的父容器中的bean。parent属性值既可以是目标bean的id值,也可以是name属性值。而且目标bean必须在当前容器的父容器中。使用parent属性的主要用途是为了用某个与父容器中的bean同名的代理来包装父容器中的一个bean(例如,子上下文中的一个bean定义覆盖了他的父bean)。
<!-- in the parent context -->
<bean id="accountService" class="com.foo.SimpleAccountService">
<!-- insert dependencies as required as here -->
</bean>
<!-- in the child (descendant) context -->
[code="java"]
<bean id="accountService" <-- notice that the name of this bean is the same as the name of the 'parent' bean
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target">
<ref parent="accountService"/> <-- notice how we refer to the parent bean
</property>
<!-- insert other configuration and dependencies as required as here -->
</bean>
[b]3.3.3.4. 集合[/b]
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@somecompany.org</prop>
<prop key="support">support@somecompany.org</prop>
<prop key="development">development@somecompany.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry>
<key>
<value>yup an entry</value>
</key>
<value>just some string</value>
</entry>
<entry>
<key>
<value>yup a ref</value>
</key>
<ref bean="myDataSource" />
</entry>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
[b]</bean>[/code]
3.3.3.4.1. 集合合并[/b]
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@somecompany.com</prop>
<prop key="support">support@somecompany.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the *child* collection definition -->
<props merge="true">
<prop key="sales">sales@somecompany.com</prop>
<prop key="support">support@somecompany.co.uk</prop>
</props>
</property>
</bean>
<beans>
不同的集合类型是不能合并(如map和 list是不能合并的),否则将会抛出相应的Exception。merge属性必须在继承的子bean中定义,而在父bean的集合属性上指定的merge属性将被忽略。
[b]3.3.3.4.2. 强类型集合(仅适用于Java5+)[/b]
public class Foo {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<beans>
<bean id="foo" class="x.y.Foo">
<property name="accounts">
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
</property>
</bean>
</beans>
[b]3.3.3.5. Nulls[/b]
注意区别空串
[b]3.3.3.6. XML-based configuration metadata shortcuts[/b]
<property name="myProperty">
<value>hello</value>
</property>
<constructor-arg>
<value>hello</value>
</constructor-arg>
<entry key="myKey">
<value>hello</value>
</entry>
等同于
<property name="myProperty" value="hello"/>
<constructor-arg value="hello"/>
<entry key="myKey" value="hello"/>
<property/>和<constructor-arg/>支持类似的简写属性ref,它可能用来替代整个内嵌的<ref/>元素。
<property name="myProperty">
<ref bean="myBean">
</property>
<constructor-arg>
<ref bean="myBean">
</constructor-arg>
等同于
<property name="myProperty" ref="myBean"/>
<constructor-arg ref="myBean"/>
map中entry元素的简写形式为key/key-ref 和 value /value-ref属性
<entry>
<key>
<ref bean="myKeyBean" />
</key>
<ref bean="myValueBean" />
</entry>
等同于
<entry key-ref="myKeyBean" value-ref="myValueBean"/>
[b]3.3.3.7. 组合属性名称[/b]
除了最后一个属性外,只要其他属性值不为null,组合或嵌套属性名是完全合法的
<bean id="foo" class="foo.Bar">
<property name="fred.bob.sammy" value="123" />
</bean>
3.3.4. 使用depends-on
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
若需要表达对多个bean的依赖,可以在'depends-on'中将指定的多个bean名字用分隔符进行分隔,分隔符可以是逗号、空格及分号等:
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
[b]3.3.5. 延迟初始化bean[/b]
ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的singleton bean。
有时候这种默认处理可能并不是你想要的。如果你不想让一个singleton bean在ApplicationContext实现在初始化时被提前实例化,那么可以将bean设置为延迟实例化。一个延迟初始化bean将告诉IoC 容器是在启动时还是在第一次被用到时实例化。
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true">
<!-- various properties here... -->
</bean>
<bean name="not.lazy" class="com.foo.AnotherBean">
<!-- various properties here... -->
</bean>
需要说明的是,如果一个bean被设置为延迟初始化,而另一个非延迟初始化的singleton bean依赖于它,那么当ApplicationContext提前实例化singleton bean时,它必须也确保所有上述singleton 依赖bean也被预先初始化,当然也包括设置为延迟实例化的bean。因此,如果Ioc容器在启动的时候创建了那些设置为延迟实例化的bean的实例,你也不要觉得奇怪,因为那些延迟初始化的bean可能在配置的某个地方被注入到了一个非延迟初始化singleton bean里面。
在容器层次中通过在<beans/>元素上使用'default-lazy-init'属性来控制延迟初始化也是可能的。如下面的配置:
<beans default-lazy-init="true">
<!-- no beans will be eagerly pre-instantiated... -->
</beans>
[b]3.3.6. 自动装配(autowire)协作者[/b]
[img]C:\Documents and Settings\Administrator\桌面\2222.bmp[/img]
[b]3.3.6.1. 设置Bean使自动装配失效[/b]
<bean/>元素的 autowire-candidate属性可被设为false,这样容器在查找自动装配对象时将不考虑该bean
[b]3.3.7. 依赖检查[/b]
dependency-check
[img]C:\Documents and Settings\Administrator\桌面\333.bmp[/img]