一、依赖注入
依赖注入有构造函数注入和设置函数注入,两种方式可以结合使用,在通过构造函数注入后,还可以继续通过设置函数注入。
1、构造函数注入
(1)定义:Ioc容器调用一个带参数的构造函数或者带参数的静态工厂方法在实例化bean的时候把依赖注入到目标bean中,每个参数代表一个依赖。
(2)xml配置:constructor-arg标签可以包含type, index, name等属性来指明哪个参数对应哪个值。假设有构造函数:public ExampleBean(int years, String ultimateAnswer)。
那么xml配置为(方式一):通过构造函数的参数类型来区分,我们知道7500000对应的是构造函数int型参数years,42对应String型的ultimateAnswer
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg type="int" value="7500000"/> <constructor-arg type="java.lang.String" value="42"/> </bean>
也可以为(方式二):通过构造函数的参数索引来区分。
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg index="0" value="7500000"/> <constructor-arg index="1" value="42"/> </bean>
还可以为(方式三):通过构造函数的参数名称来区分。
<bean id="exampleBean" class="examples.ExampleBean"> <constructor-arg name="years" value="7500000"/> <constructor-arg name="ultimateanswer" value="42"/> </bean>
不过要记住,使用方式三,在编译代码的时候必须开启Debug模式,这样参数的名字信息才能编译进目标代码中。如果没有使用debug模式编译代码的话,我们可以使用JDK的@ConstructorProperties注解来显示地给构造函数参数命名。如:
@ConstructorProperties({"years", "ultimateAnswer"}) public ExampleBean(int years, String ultimateAnswer) { this.years = years; this.ultimateAnswer = ultimateAnswer; }
2、设置函数注入
(1)定义:在调用无参构造函数或者无参静态工厂方法实例化bean后,再通过设置函数(Setter)把依赖注入到目标bean中。
3、通过构造函数注入,要小心出现循环依赖的情况。出现这种情况,Spring Ioc容器报BeanCurrentlyInCreationException异常,可以通过设置器注入的方式来解决循环依赖。
4、依赖注入xml配置举例:通过bean标签的constructor-arg及property子标签来实现上面两种方式的依赖注入
(1)构造函数注入:通过constructor-arg标签注入依赖,注意ref可以作为子标签,也可以作为标签属性出现。
<bean id="exampleBean" class="examples.ExampleBean"> <!-- constructor injection using the nested <ref/> element --> <constructor-arg> <ref bean="anotherExampleBean"/>(1 </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"/>
(2)通过静态工厂方法或者实例工厂方法和构造函数类似,也是使用constructor-arg标签,如:
<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"/>
5、更多配置细节
(1)value属性用来表示直接值,比如原始数据类型,字符串等,如:<property name="url" value="jdbc:mysql://localhost:3306/mydb"/>
Spring通过conversion service把这些值从一个字符串转换成实际的数据类型。
(2)idref子标签把容器中一个bean的id传递到目标bean。如:<bean id="client"><property name="targetName"><idref bean="theTargetBean"/></property></bean>
(3)ref标签是property和constructor-arg标签最后一个子标签,使用它设置一个bean的属性为另一个bean的引用,这个标签可以有bean, local , parent属性
(4)内部bean,在property和constructor-arg标签里可以使用<bean>标签定义内部bean
(5)在property和constructor-arg标签里可以使用props, map, set, list标签,分别注入Java的集合类型Properties, Map, Set, List
(6)null标签表示null值,“”表示空字符串,如:<property name="email"><null/></property>, <property name="email" value=""/>
(7)使用p命名空间可以代替<property>子标签,直接在bean的属性里定义设置函数方式定义的依赖(注意属性的命名方式:p:{propname}[-ref]),如:
<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.xsd"> <bean name="john-classic" class="com.example.Person"> <property name="name" value="John Doe"/> <property name="spouse" ref="jane"/> </bean> <bean name="john-modern" class="com.example.Person" p:name="John Doe" p:spouse-ref="jane"/> <bean name="jane" class="com.example.Person"> <property name="name" value="Jane Doe"/> </bean> </beans>
(8)和p类似,我们使用c命名空间可以代替<constructor-arg>子标签,直接在bean的属性里定义构造函数方式定义的依赖(注意属性的命名方式:c:{argname|_index}[-ref]),如:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:c="http://www.springframework.org/schema/c" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bar" class="x.y.Bar"/> <bean id="baz" class="x.y.Baz"/> <-- c-namespace declaration --> <bean id="foo" class="x.y.Foo" c:bar-ref="bar" c:baz-ref="baz" c:email="foo@bar.com"> <-- c-namespace index declaration --> <bean id="foo" class="x.y.Foo" c:_0-ref="bar" c:_1-ref="baz"> </beans>
(9)复合的属性名,如下,意思就是foo表示的bean,含有一个fred的属性,fred又含有一个bob属性,bob再含有一个sammy属性,最后sammy的属性值为123.
<bean id="foo" class="foo.Bar"> <property name="fred.bob.sammy" value="123" /> </bean>