一. Spring依赖关系的配置
UML类图中类之间的关系
UML类图中的关系包含:依赖关系、泛化关系、关联关系、聚合关系、组合关系、实现关系
1. 依赖关系
一种使用的关系,A类的变化引起了B类的变化,就说明B依赖于A。依赖关系有如下3种情况:
1. A类是B类(方法中)的局部变量
2. A类是B类方法中的参数
3. A类向B类传递消息
2. 泛化关系
类与类、接口和接口之间的继承关系。A类是B类和C类的父类,则A类具有B类和C类的共同特征,是B类和C类的泛化。
3. 关联关系
类之间的联系,如:客户和订单。
- 双向关联
- 单项关联
- 自关联
- 重数性关联
4. 聚合关系
整体与部分的关系,整体和部分可以分开。如:Car、Engine的关系,Computor、keyboard、mouse的关系
5. 组合关系
整体与部分的关系,整体和部分不能分开,如:head、mouth的关系
6. 实现关系
接口和类之间存在实现关系。
IoC的依赖关系
- Bean对Ioc容器的依赖
- Ioc容器注入Bean的依赖资源,如: 类、文件、常量数据等
依赖注入带来的好处?
- 可以动态替换Bean,使程序更加灵活
- 更好实践面向接口编程
- 更好实践优先使用对象组合,而不是继承
面向接口编程、和优先使用对象组合可以降低耦合,增加代码复用。
Ioc容器依赖注入方式
Ioc有2种依赖注入方式:构造器注入、setter注入
构造器注入
构造器:
public HelloServiceImpl3(String message, HelloService subService) {
this.message = message;
this.subService = subService;
}
1. 通过参数索引注入
<bean id = "helloService1" class="com.kiikgu.HelloServiceImpl">
<constructor-arg index="0" value="Hello World 1" />
</bean>
<bean id="helloSerivceByIndex" class="com.kiikgu.HelloServiceImpl3">
<constructor-arg index="0" value="Hello World 3" />
<constructor-arg index="1" ref="helloService1" />
</bean>
- index参数在构造器中的位置
2. 通过参数类型注入
<bean id="helloServiceByType" class="com.kiikgu.HelloServiceImpl3">
<constructor-arg type="java.lang.String" value="hello world 4" />
<constructor-arg type="com.kiikgu.HelloService" ref="helloService1" />
</bean>
3. 通过参数名称注入
<bean id="helloServiceByName" class="com.kiikgu.HelloServiceImpl3">
<constructor-arg name="message" value="hello world" />
<constructor-arg name="subService" value="helloService1" />
</bean>
4. 通过静态工厂和实例工厂注入
以静态工厂举例:
<bean id="helloServiceByFactoryIndex" class="com.kiikgu.HelloServiceFactory" factory-method="getHelloService">
<constructor-arg index="0" value="Hello World 3" />
<constructor-arg index="1" ref="helloService1" />
</bean>
<bean id="helloServiceByFactoryType" class="com.kiikgu.HelloServiceFactory" factory-method="getHelloService">
<constructor-arg type="java.lang.String" value="hello world 4" />
<constructor-arg type="com.kiikgu.HelloService" ref="helloService1" />
</bean>
<bean id="helloServiceByFactoryName" class="com.kiikgu.HelloServiceFactory" factory-method="getHelloService">
<constructor-arg name="message" value="hello world 5" />
<constructor-arg name="subService" ref="helloService1" />
</bean>
setter注入
<bean id="helloService2" class="com.kiikgu.HelloServiceImpl">
<property name="message" value="hello world" />
<property name="innerService" ref="helloService1" />
</bean>
注入常量
<bean id="helloService2" class="com.kiikgu.HelloServiceImpl">
<property name="flag" value="on" />
<property name="message" value="hello world" />
<property name="innerService" ref="helloService1" />
</bean>
在注入boolean类型的域时,Spring做了适配,值可以填:”true/false“、”yes/no“、”on/off“、”1/0“
注入集合、数组和词典
Bean定义
public class CollectionDIBean {
private List<String> list;
private Set<String> set;
private Collection<String> collection;
private String[] array;
private String[][] array1;
private Map<String, Integer> map;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Set<String> getSet() {
return set;
}
public void setSet(Set<String> set) {
this.set = set;
}
public Collection<String> getCollection() {
return collection;
}
public void setCollection(Collection<String> collection) {
this.collection = collection;
}
public String[] getArray() {
return array;
}
public void setArray(String[] array) {
this.array = array;
}
public String[][] getArray1() {
return array1;
}
public void setArray1(String[][] array1) {
this.array1 = array1;
}
public Map<String, Integer> getMap() {
return map;
}
public void setMap(Map<String, Integer> map) {
this.map = map;
}
public void printList() {
System.out.println(Arrays.toString(list.toArray()));
}
public void printSet() {
System.out.println(Arrays.toString(set.toArray()));
}
public void printCollection() {
System.out.println(Arrays.toString(collection.toArray()));
}
public void printArray() {
System.out.println(Arrays.toString(array));
}
public void printArray1() {
System.out.println(Arrays.deepToString(array1));
}
public void printMap() {
for (String key : map.keySet()) {
System.out.println(String.format("%s:%s", key, map.get(key)));
}
}
}
配置文件
<bean id="collectionDIBean" class="com.kiikgu.CollectionDIBean">
<!--list -->
<property name="list">
<list value-type="java.lang.String">
<value>cat</value>
<value>dog</value>
<value>fox</value>
<value>panda</value>
</list>
</property>
<!--set-->
<property name="set">
<set value-type="java.lang.String">
<value>123</value>
<value>123</value>
<value>345</value>
</set>
</property>
<!--collection-->
<property name="collection">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<!--array-->
<property name="array">
<array>
<value>a1</value>
<value>a2</value>
<value>a3</value>
</array>
</property>
<!--array-->
<property name="array1">
<array>
<array>
<value>a11</value>
<value>a12</value>
</array>
<array>
<value>a21</value>
<value>a22</value>
</array>
</array>
</property>
<!--map-->
<property name="map">
<map>
<entry key="k1" value="1" />
<entry key="k2" value="2" />
<entry key="k3" value="3" />
</map>
</property>
</bean>
测试一下:
CollectionDIBean collectionDIBean = context.getBean("collectionDIBean", CollectionDIBean.class);
collectionDIBean.printList();
collectionDIBean.printSet();
collectionDIBean.printCollection();
collectionDIBean.printArray();
collectionDIBean.printArray1();
collectionDIBean.printMap();
[cat, dog, fox, panda]
[123, 345]
[1, 2, 3]
[a1, a2, a3]
[[a11, a12], [a21, a22]]
k1:1
k2:2
k3:3
注入Properites
bean定义
public class PropertiesDIBean {
private Properties values;
public Properties getValues() {
return values;
}
public void setValues(Properties values) {
this.values = values;
}
public void printValues() {
for (Object key : values.keySet()) {
System.out.println(String.format("%s : %s", key, values.get(key)));
}
}
}
配置
<bean id="propertiesDIBean" class="com.kiikgu.PropertiesDIBean">
<property name="values">
<props>
<prop key="p1">v1</prop>
<prop key="p2">v2</prop>
<prop key="p3">v3</prop>
</props>
</property>
</bean>
测试一下吧:
PropertiesDIBean propertiesDIBean = context.getBean("propertiesDIBean", PropertiesDIBean.class);
propertiesDIBean.printValues();
p3 : v3
p2 : v2
p1 : v1
引用其它Bean
基本配置:使用ref标签
<bean id="helloService3" class="com.kiikgu.HelloServiceImpl3">
<constructor-arg type="java.lang.String" value="hello ref" />
<constructor-arg type="com.kiikgu.HelloService">
<ref bean="helloService1" />
</constructor-arg>
</bean>
<bean id="helloService3" class="com.kiikgu.HelloServiceImpl3">
<constructor-arg type="java.lang.String" value="hello ref" />
<constructor-arg type="com.kiikgu.HelloService" ref="helloService1"/>
</bean>
高级配置:\
引用父容器中的bean
<!--spring-learn-parent.xml-->
<bean id = "helloService1" name="helloService1Name" class="com.kiikgu.HelloServiceImpl">
<constructor-arg index="0" value="Hello parent" />
<property name="flag" value="true" />
</bean>
<!--spring-learn.xml -->
<bean id = "helloService1" name="helloService1Name" class="com.kiikgu.HelloServiceImpl">
<constructor-arg index="0" value="hello son" />
<property name="flag" value="yes" />
</bean>
<bean id="helloService3" class="com.kiikgu.HelloServiceImpl3">
<property name="message" value="123" />
<property name="subService">
<ref parent="helloService1" />
</property>
</bean>
测试一下:
ApplicationContext parentContext = new ClassPathXmlApplicationContext("spring-learn-parent.xml");
ApplicationContext childContext = new ClassPathXmlApplicationContext(new String[]{"spring-learn.xml"}, parentContext);
HelloService helloService = childContext.getBean("helloService3", HelloService.class);
helloService.sayHello();
Hello parent
123
注入内部Bean
内部bean是在\或\内部用\标签定义的Bean,该内部bean对其它外部bean不可见
<bean id="helloService4" class="com.kiikgu.HelloServiceImpl3">
<property name="message" value="outer bean" />
<property name="subService">
<bean id="innerBean" class="com.kiikgu.HelloServiceImpl">
<constructor-arg name="message" value="inner bean" />
<property name="flag" value="1"/>
</bean>
</property>
</bean>
注入null
使用标签 \
<bean id="helloService4" class="com.kiikgu.HelloServiceImpl3">
<property name="message"><null /></property>
对象图导航注入
Bean定义
public class NavigationDIBeanC {
private String name;
}
public class NavigationDIBeanB {
private NavigationDIBeanC c;
private Map<String, String> values;
}
public class NavigationDIBeanA {
private NavigationDIBeanB b;
}
省略了get、set方法
配置
<bean id="nc" class="com.kiikgu.NavigationDIBeanC" />
<bean id="nb" class="com.kiikgu.NavigationDIBeanB" />
<bean id="na" class="com.kiikgu.NavigationDIBeanA">
<property name="b" ref="nb" />
<property name="b.c" ref="nc" />
<property name="b.values">
<map>
<entry key="123" value="123" />
</map>
</property>
<property name="b.c.name" value="test" />
</bean>
- 这种方法不推荐使用
使用p命名空间简化setter注入
<?xml version="1.0" encoding="UTF-8"?>
<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 id="nc" class="com.kiikgu.NavigationDIBeanC" p:name="test1" />
指定命名空间:xmlns:p=”http://www.springframework.org/schema/p”
<bean id=”nc” class=”com.kiikgu.NavigationDIBeanC” p:name=”test1” />
相当于:
<property name=”name” value=”test1” />
总结
本节介绍了Spring DI的配置,包括:类之间的关系、Spring Ioc容器对Bean依赖关系的各种注入方式。