Spring 核心技术——IoC 之 DI (1)
2017-03-18 14:51
453 查看
DI 简介
DI 的方式
1 设值注入
JavaBean
applicationContextxml
测试方法
测试结果
2 构造器注入
JavaBean
applicationContextxml
测试方法
测试结果
DI 的类型
1 其他 bean
11 idref 元素
12 ref 元素
121 ref bean
122 ref local
123 ref parent
2 内部 bean
3 集合
31 常规使用
32 集合整合
33 强类型集合
4 Null 或空字符串
41 空字符串
42 Null
5 复合嵌套属性名
即依赖注入,提供普通的Java方法让容器去决定依赖关系。容器全权负责的组件的装配,它会把符合依赖关系的对象通过 JavaBean 属性或者构造函数传递给需要的对象。
注意:通常,我们会将 IoC 与 DI 作为同一个概念理解,其实 IoC 是一个很大的概念,DI 只是其中一个比较流行的实现策略。只是对于 Spring 而言,其 IoC 容器就是通过 DI 实现的,所以也就不再严格区分。
设值注入:通过JavaBean属性注射依赖关系
构造器注入:将依赖关系作为构造函数参数传入
其中,除了可以通过最常用的标签属性
与
上面的配置,在运行时完全等价于下面的配置
注意:
另外,在 4.0 版本之前,
3.1.2.1
3.1.2.2
这个和
3.1.2.3
通过使用
另外,
List:
Set:
Map:
Properties:
其中,map 的 key/value 和 set 的 value 还可以通过下面任意一种元素指定:
注意:在整合中,如果父子集合类型不一致,是不能整合的。
此例中,当注入
上面的配置等价于
上面的配置等价于
上例中,
DI 的方式
1 设值注入
JavaBean
applicationContextxml
测试方法
测试结果
2 构造器注入
JavaBean
applicationContextxml
测试方法
测试结果
DI 的类型
1 其他 bean
11 idref 元素
12 ref 元素
121 ref bean
122 ref local
123 ref parent
2 内部 bean
3 集合
31 常规使用
32 集合整合
33 强类型集合
4 Null 或空字符串
41 空字符串
42 Null
5 复合嵌套属性名
1 DI 简介
DI(Dependency Injection)即依赖注入,提供普通的Java方法让容器去决定依赖关系。容器全权负责的组件的装配,它会把符合依赖关系的对象通过 JavaBean 属性或者构造函数传递给需要的对象。
注意:通常,我们会将 IoC 与 DI 作为同一个概念理解,其实 IoC 是一个很大的概念,DI 只是其中一个比较流行的实现策略。只是对于 Spring 而言,其 IoC 容器就是通过 DI 实现的,所以也就不再严格区分。
2 DI 的方式
在 Spring 中,主要有以下两种方式:设值注入:通过JavaBean属性注射依赖关系
构造器注入:将依赖关系作为构造函数参数传入
2.1 设值注入
JavaBean
package com.jyhuang.spring.DI.setter_based; public class People { private String name; private int age; // 使用设值注入,必须提供对应属性的 setter 方法 // getter...setter @Override public String toString() { return "People{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
applicationContext.xml
使用<property>标签进行属性的注入,其中标签属性
name指定 JavaBean 中对应的属性名,标签属性
value指定需要注入的值,这两个标签都是必须的。
<bean id="people" class="com.jyhuang.spring.DI.setter_based.People"> <property name="name" value="Tom"/> <property name="age" value="20"/> </bean>
测试方法
@Test public void test() { ApplicationContext ctx = new ClassPathXmlApplicationContext( "com/jyhuang/spring/DI/setter_based/applicationContext.xml"); People people = (People) ctx.getBean("people"); System.out.println(people.toString()); }
测试结果
People{name='Tom', age=20}
2.2 构造器注入
JavaBean
package com.jyhuang.spring.DI.constructor_based; public class People { private String name; private int age; public People() {} // 使用构造器注入,必须提供以对应属性为参数的构造方法 public People(String name, int age) { this.name = name; this.age = age; } // getter...setter @Override public String toString() { return "People{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
applicationContext.xml
使用<constructor-arg>标签进行构造器注入。
其中,除了可以通过最常用的标签属性
name和
value进行注入外,
index和
type属性同样可以,这两个属性分别对应构造器中传参的索引和参数类型。三个属性可单独或组合使用,但必须保证最终能精确定位到需要注入值的那个参数。
与
<property不同,此标签的
name属性不是必须的。默认情况下,会根据参数类型自动注入对应的属性,只需要指定
value即可,即使配置的顺序与构造器的传参顺序不一致,一样能正确注入,但前提是能通过参数类型唯一定位;如果参数类型一致,Spring 会根据配置顺序依次注入。为了避免麻烦,建议配置时手动定位。
<bean id="people" class="com.jyhuang.spring.DI.constructor_based.People"> <!--<constructor-arg name="name" value="Tom"/>--> <!--<constructor-arg name="age" value="20"/>--> <constructor-arg index="0" type="java.lang.String" name="name" value="Tom"/> <constructor-arg index="1" type="int" name="age" value="20"/> </bean>
测试方法
@Test public void test() { ApplicationContext ctx = new ClassPathXmlApplicationContext( "com/jyhuang/spring/DI/constructor_based/applicationContext.xml"); People p = (People) ctx.getBean("people"); System.out.println(p); }
测试结果
fc4cPeople{name='Tom', age=20}
3 DI 的类型
除了之前例子中提及到的基本数据类型和 String 等直接值以外,依赖注入的类型还有很多,下面作简要说明。3.1 其他 bean
注入其他 JavaBean,也叫合作 bean 或者协同 bean,主要有以下两种方式:idref和
ref,这两个元素都可以作为
<constructor-arg>和
<property>标签的子元素来指定需要注入的 bean。
3.1.1 idref 元素
<bean id="theTargetBean" class="..."/> <bean id="theClientBean" class="..."> <property name="targetName"> <idref bean="theTargetBean" /> </property> </bean>
上面的配置,在运行时完全等价于下面的配置
<bean id="theTargetBean" class="..." /> <bean id="client" class="..."> <property name="targetName" value="theTargetBean" /> </bean>
idref bean和
property value注入的值都是字符串类型,只是
idref注入的是容器中已经存在的 bean 的 id 值,该元素在容器发布时,会对注入的值进行校验,判断容器中是否真的存在这样一个 bean,该 bean 的 id 与
idref bean配置值相同,而
property value则会直接把值作为字符串注入。
注意:
idref注入的是字符串类型的值,只是这个值必须对应某个 bean 的 id 值,它并不是真地注入一个 bean,所以,接收该值的属性也必须是字符串。
另外,在 4.0 版本之前,
idref有个
local属性,但从 4.0 的 beans xsd 开始已经不再被支持。当升级版本时,只需要简单地将
idref local修改成
idref bean即可。
3.1.2 ref 元素
与idref元素不同,
ref元素注入的是 bean 实例,而且,
ref bean的值不仅可以是其他 bean 的 id 属性值,还可以是 name 属性值。
3.1.2.1 ref bean
<ref bean="someBean"/>
3.1.2.2 ref local
这个和 idref一样,从 4.0 的 beans xsd 开始,Spring 就不再支持,此处不再说明。
3.1.2.3 ref parent
通过使用 ref parent来引用当前容器的父容器中的 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 --> <bean id="accountService" <!-- bean name is the same as 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 here --> </bean>
另外,
ref不仅可以作为
<constructor-arg>和
<property>的子标签,还可以作为属性进行 bean 的注入,此时,就等价于
ref bean。
<property name="target" ref="someBean"/>
3.2 内部 bean
使用<bean/>标签在
<constructor-arg>和
<property>中定义内部 bean。此时,无须为该内部 bean 指定 id/name 属性,即使指定,容器也会忽略,因为该内部 bean 只能给它对应的外部 bean 使用。另外,对于内部 bean 的 scope 属性,容器也会忽略,因为内部 bean 永远都是匿名的,且随着外部 bean 的创建而创建。
<bean id="outer" class="..."> <!-- instead of using a reference to a target bean, simply define the target bean inline --> <property name="target"> <bean class="com.example.Person"> <!-- this is the inner bean --> <property name="name" value="Fiona Apple"/> <property name="age" value="25"/> </bean> </property> </bean>
3.3 集合
Spring 主要提供了如下类型的集合注入List:
<list/>
Set:
<set/>
Map:
<map/>
Properties:
<props/>
3.3.1 常规使用
<bean id="moreComplexObject" class="example.ComplexObject"> <!-- results in a setAdminEmails(java.util.Properties) call --> <property name="adminEmails"> <props> <prop key="administrator">administrator@example.org</prop> <prop key="support">support@example.org</prop> <prop key="development">development@example.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="an entry" value="just some string"/> <entry key ="a ref" value-ref="myDataSource"/> </map> </property> <!-- results in a setSomeSet(java.util.Set) call --> <property name="someSet"> <set> <value>just some string</value> <ref bean="myDataSource" /> </set> </property> </bean>
其中,map 的 key/value 和 set 的 value 还可以通过下面任意一种元素指定:
bean | ref | idref | list | set | map | props | value | null
3.3.2 集合整合
集合整合实际就是集合继承,Spring 是支持一个应用定义父类型的集合元素,然后使用子类型的集合元素去继承和覆盖父类型集合元素中的值,只需要在子集合定义时显示的指定merge=true,适用于上述列举的四种集合类型。
<beans> <bean id="parent" abstract="true" class="example.ComplexObject"> <property name="adminEmails"> <props> <prop key="administrator">administrator@example.com</prop> <prop key="support">support@example.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@example.com</prop> <prop key="support">support@example.co.uk</prop> </props> </property> </bean> <beans>
注意:在整合中,如果父子集合类型不一致,是不能整合的。
3.3.3 强类型集合
从 Java 5 开始引入了泛型,所以,对于指定了元素类型的集合注入,需要注意类型匹配问题。由于 Spring 自己提供了基本类型转换支持,所以,默认情况下,Spring 会根据目标类型对注入的值进行自动转换。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>
此例中,当注入
9.99,
2.75和
3.99时,都会自动转换成 Float 类型。
3.4 Null 或空字符串
3.4.1 空字符串
<bean class="ExampleBean"> <property name="email" value=""/> </bean>
上面的配置等价于
exampleBean.setEmail("")
3.4.2 Null
null 值的注入比较特殊,需要使用<null/>元素来完成。
<bean class="ExampleBean"> <property name="email"> <null/> </property> </bean>
上面的配置等价于
exampleBean.setEmail(null)
3.5 复合/嵌套属性名
Spring 支持对象.属性这种嵌套的方式进行属性值的注入,但必须保证在嵌套过程的对象/属性必须存在且不能为 null,否则,会抛出异常。
<bean id="foo" class="foo.Bar"> <property name="fred.bob.sammy" value="123" /> </bean>
上例中,
Bar必须有
fred对象作为属性,
fred对象必须有
bob对象作为属性,
bob对象必须有
sammy对象作为属性;在注入
123之前,
Bar,
fred和
bob对象必须已经初始化,不能为 null,否则会抛出
NullPointerException。
相关文章推荐
- Spring核心技术阐述(IOC、DI、AOP)
- Spring核心技术阐述(IOC、DI、AOP)
- Spring 核心技术——IoC 之 DI (2)
- Spring的核心技术:IoC和DI
- Spring.Net 技术简介 IOC and DI
- (四)Spring核心思想 - IOC与DI
- Spring 核心技术IoC容器(二)
- Spring核心技术IoC容器(八)
- Spring核心技术(1)控制反转(Inversion of Control,IoC)理论
- Spring核心技术IoC容器(七)
- Spring核心技术IoC容器(五)
- 1、Spring3核心技术-IoC(一)
- Spring 核心技术IoC容器 (三)
- Spring核心技术Ioc和AOP
- Spring核心技术IoC容器(四)
- 详解Spring IOC 与 DI 核心原理
- Spring核心技术之Ioc和AOP
- Spring3核心技术之IOC控制反转
- Spring3核心技术之DI依赖注入
- Spring核心技术IoC容器(六)