常量注入:
<!-- 常量注入 --> <bean id="AfxMessage" class="java.lang.String"> <constructor-arg index="0" value="Hello Spring by id" /> </bean> <bean id="beanSetAfx" class="com.constructor.HelloImplConstr"> <property name="message"> <idref bean="AfxMessage" /> </property> <property name="index" value="5" /> </bean>
//setter注入 +常量注入 根据set get 函数进行注入
HelloApi helloApi5 = context.getBean("beanSetAfx",HelloApi.class);
helloApi5.sayHello();
/**
* 构造器注入可以根据参数索引注入、参数类型注入或Spring3支持的参数名注入,
* 但参数名注入是有限制的,需要使用在编译程序时打开调试模式
* (即在编译时使用“javac –g:vars”在class文件中生成变量调试信息,默认是不包含变量调试信息的,
* 从而能获取参数名字,否则获取不到参数名字)
* 或在构造器上使用@ConstructorProperties(java.beans.ConstructorProperties)注解来指定参数名。
*/
public class HelloImplConstr implements HelloApi {
private String message;
private int index;
public HelloImplConstr(){
}
@ConstructorProperties({"message","index"})
public HelloImplConstr(String message,int index){
this.message = message;
this.index = index;
}
public void sayHello() {
System.out.println(this.index+":"+this.message);
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
第一种方式可以在容器初始化时校验被引用的Bean是否存在,如果不存在将抛出异常,
而第二种方式只有在Bean实际使用时才能发现传入的Bean的ID是否正确,
可能发生不可预料的错误。因此如果想注入Bean的ID,推荐使用第一种方式。
将在容器初始化时校验注入的ID对于的Bean是否存在,如果不存在将抛出异常。
将在XML解析时校验注入的ID对于的Bean在当前配置文件中是否存在,
如果不存在将抛出异常,它不同于是校验发生在XML解析式而非容器初始化时,
且只检查当前配置文件中是否存在相应的Bean。
集合注入:
<!-- list set 注入集合--> <bean id="listBean" class="com.dilist.HelloDiList"> <property name="valuesList"> <!-- <list value-type="java.lang.String" merge="default"> --> <list><!-- <set> --> <value>1</value> <value>2</value> <value>3</value> </list> </property> </bean> <!-- Collection类型:因为Collection类型是Set和List类型的基类型, 所以使用<set>或<list>标签都可以进行注入,配置方式完全和以上配置方式一样, 只是将测试类属性改成“Collection”类型, --> <!-- 注入数组类型 --> <bean id="arrayBean" class="com.dilist.HelloDiList"> <property name="array"> <array value-type="java.lang.String" merge="default"> <value>1</value> <value>2</value> </array> </property> <property name="array2"> <array> <array> <value>1</value> <value>2</value> </array> <array> <value>4</value> <value>5</value> </array> </array> </property> </bean>
public class HelloDiList implements HelloApi,HelloApiArry{
private String array[];
private String array2[][];
private List<String> valuesList;
public void sayHello() {
for (int i = 0; i < valuesList.size(); i++) {
System.out.println(valuesList.get(i));
}
}
public void sayHelloArray(){
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
for (int i = 0; i < array2.length; i++) {
for (int j = 0; j < array2[i].length; j++) {
System.out.println(array2[i][j]);
}
}
}
public List<String> getValuesList() {
return valuesList;
}
public void setValuesList(List<String> valuesList) {
this.valuesList = valuesList;
}
public String[] getArray() {
return array;
}
public void setArray(String[] array) {
this.array = array;
}
public String[][] getArray2() {
return array2;
}
public void setArray2(String[][] array2) {
this.array2 = array2;
}
}
调用处:
//读取配置文件实例化一个Ioc容器
ApplicationContext context = new ClassPathXmlApplicationContext("helloworld.xml");
//setter注入 +list set常量 注入集合、数组和字典
HelloApi helloApi = context.getBean("listBean",HelloApi.class);
helloApi.sayHello();
//setter注入 +数组 一维 二维 常量 注入集合、数组和字典
HelloApiArry helloApi2 = context.getBean("arrayBean",HelloApiArry.class);
helloApi2.sayHelloArray();
Map注入
/**
* 注入字典(Map)类型:字典类型是包含键值对数据的数据结构,需要使用<map>标签来配置注入,
* 其属性“key-type”和“value-type”分别指定“键”和“值”的数据类型,其含义和<list>标签的“value-type”含义一样,
* 在此就不罗嗦了,并使用<key>子标签来指定键数据,<value>子标签来指定键对应的值数据
*/
public class HelloDiMap implements HelloApi {
private Map<String, String> mapValues;
public void sayHello() {
for (String key : mapValues.keySet()) {
System.out.println(key+":"+mapValues.get(key));
}
}
public Map<String, String> getMapValues() {
return mapValues;
}
public void setMapValues(Map<String, String> mapValues) {
this.mapValues = mapValues;
}
}
两种配置方法
<!-- 注入map类型 --> <bean id="mapBean" class="com.dilist.HelloDiMap"> <property name="mapValues"> <map key-type="java.lang.String" value-type="java.lang.String"> <entry> <key> <value>1</value> </key> <value>11</value> </entry> <entry key="2" value="22" /> </map> </property> </bean>
Properties 注入:
/**
* Properties注入:Spring能注入java.util.Properties类型数据,需要使用<props>标签来配置注入,
* 键和值类型必须是String,不能变,子标签<prop key=”键”>值</prop>来指定键值对
*/
public class HelloDiProperties implements HelloApi {
private Properties properties;
private Properties properties2;
public void sayHello() {
for(Object key :properties.keySet()){
System.out.println(key+":"+properties.getProperty((String)key));
}
for(Object key :properties2.keySet()){
System.out.println(key+":"+properties2.getProperty((String)key));
}
}
public Properties getProperties() {
return properties;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
public Properties getProperties2() {
return properties2;
}
public void setProperties2(Properties properties2) {
this.properties2 = properties2;
}
}
properties XML配置注入
<!-- 注入properties类型 --> <bean id="properBean" class="com.dilist.HelloDiProperties"> <property name="properties"> <props value-type="int" merge="default"><!-- 虽然指定value-type,但是不起作用 --> <prop key="1">1sss</prop> <!-- Properties 建和值都是String类型 --> <prop key="2">2</prop> </props> </property> <property name="properties2"> <value> <!-- 分隔符可以是 “换行”、“;”、“,” 不建议该方式,优先选择第一种方式 --> 1=11 2=22;<!-- 这样的分隔符好像没用 --> 3=33, 4=44 </value> </property> </bean>
引用其它Bean
一、构造器注入方式:
(1)通过” <constructor-arg>”标签的ref属性来引用其他Bean
(2)通过” <constructor-arg>”标签的子<ref>标签来引用其他Bean,使用bean属性来指定引用的Bean
二、setter注入方式:
(1)通过” <property>”标签的ref属性来引用其他Bean
(2)通过” <property>”标签的子<ref>标签来引用其他Bean,使用bean属性来指定引用的Bean
为什么要应用依赖注入,应用依赖注入能给我们带来哪些好处呢?
动态替换Bean依赖对象,程序更灵活:替换Bean依赖对象,无需修改源文件:应用依赖注入后,由于可以采用配置文件方式实现,从而能随时动态的替换Bean的依赖对象,无需修改java源文件;
更好实践面向接口编程,代码更清晰:在Bean中只需指定依赖对象的接口,接口定义依赖对象完成的功能,通过容器注入依赖实现;
更好实践优先使用对象组合,而不是类继承:因为IoC容器采用注入依赖,也就是组合对象,从而更好的实践对象组合。
- 采用对象组合,Bean的功能可能由几个依赖Bean的功能组合而成,其Bean本身可能只提供少许功能或根本无任何功能,全部委托给依赖Bean,对象组合具有动态性,能更方便的替换掉依赖Bean,从而改变Bean功能;
- 而如果采用类继承,Bean没有依赖Bean,而是采用继承方式添加新功能,,而且功能是在编译时就确定了,不具有动态性,而且采用类继承导致Bean与子Bean之间高度耦合,难以复用。
增加Bean可复用性:依赖于对象组合,Bean更可复用且复用更简单;
降低Bean之间耦合:由于我们完全采用面向接口编程,在代码中没有直接引用Bean依赖实现,全部引用接口,而且不会出现显示的创建依赖对象代码,而且这些依赖是由容器来注入,很容易替换依赖实现类,从而降低Bean与依赖之间耦合;
代码结构更清晰:要应用依赖注入,代码结构要按照规约方式进行书写,从而更好的应用一些最佳实践,因此代码结构更清晰。
从以上我们可以看出,其实依赖注入只是一种装配对象的手段,设计的类结构才是基础,如果设计的类结构不支持依赖注入,Spring IoC容器也注入不了任何东西,从而从根本上说“如何设计好类结构才是关键,依赖注入只是一种装配对象手段”。
前边IoC一章我们已经了解了Bean依赖容器,那容器如何注入Bean的依赖资源,Spring IoC容器注入依赖资源主要有以下两种基本实现方式:
构造器注入:就是容器实例化Bean时注入那些依赖,通过在在Bean定义中指定构造器参数进行注入依赖,包括实例工厂方法参数注入依赖,但静态工厂方法参数不允许注入依赖;
setter注入:通过setter方法进行注入依赖;
方法注入:能通过配置方式替换掉Bean方法,也就是通过配置改变Bean方法 功能。