@[TOC]
引入
如果我们要向类中传递数据,我们要借助于方法往里面传,这是肯定的。但是这个方法是可以有多种的。于是这里就分出来两种:
- 普通方法(set方法)
- 构造方法
然后我们再思考:依赖注入描述了在容器中建立bean与bean之间依赖关系的过程,那么如果bean运行需要的是数字或字符串呢?
也就是说我们可以再次细分:
setter注入
- 简单数据类型
- 引用数据类型
构造器注入
- 简单数据类型
- 引用数据类型
Setter注入
引用数据类型
我们之前使用的就是这种,所以我们复习一下:
- 在bean中定义引用类型属性,并提供可访问的==set==方法
public class BookServiceImpl implements BookService {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
- 配置中使用==property==标签==ref==属性注入引用类型对象
<bean id="bookService" class="impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
</bean>
<bean id="bookDao" class="imipl.BookDaoImpl"/>
简单数据类型
简单数据类型与引用数据类型差不多,区别在于配置的时候不再使用ref,而是使用value
我们接下来举一个例子:
步骤1:声明属性并提供setter方法
在BookDaoImpl类中声明对应的简单数据类型的属性,并提供对应的setter方法
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
public void save() {
System.out.println("book dao save ..."+databaseName+","+connectionNum);
}
}
步骤2:配置文件中进行注入配置
在applicationContext.xml配置文件中使用property标签注入
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="impl.BookDaoImpl">
<property name="databaseName" value="mysql"/>
<property name="connectionNum" value="10"/>
</bean>
<bean id="userDao" class="impl.UserDaoImpl"/>
<bean id="bookService" class="impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
</beans>
两个property注入标签的顺序可以任意。
结果:
==注意:==
value:后面跟的是简单数据类型,对于参数类型,Spring在注入的时候会自动转换,但是不能写成
<property name="connectionNum" value="abc"/>
这样的话,spring在将abc
转换成int类型的时候就会报错。
对于setter注入方式的基本使用就已经介绍完了,
- 对于引用数据类型使用的是
<property name="" ref=""/>
- 对于简单数据类型使用的是
<property name="" value=""/>
构造器注入
引用数据类型
步骤1:删除setter方法并提供构造方法
在BookServiceImpl类中将bookDao的setter方法删除掉,并添加带有bookDao参数的构造方法
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public BookServiceImpl(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
步骤2:配置文件中进行配置构造方式注入
在Spring配置文件中配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="impl.BookDaoImpl"/>
<bean id="bookService" class="impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
</bean>
</beans>
说明:
标签中
- ==name属性对应的值为构造函数中方法形参的参数名==,必须要保持一致。
- ref属性指向的是spring的IOC容器中其他bean对象。
简单数据类型
步骤1:添加多个简单属性并提供构造方法
修改BookDaoImpl类,添加构造方法
public class BookDaoImpl implements BookDao {
private String databaseName;
private int connectionNum;
public BookDaoImpl(String databaseName, int connectionNum) {
this.databaseName = databaseName;
this.connectionNum = connectionNum;
}
public void save() {
System.out.println("book dao save ..."+databaseName+","+connectionNum);
}
}
步骤2:配置完成多个属性构造器注入
在Spring配置文件中进行注入配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="bookDao" class="impl.BookDaoImpl">
<constructor-arg name="databaseName" value="mysql"/>
<constructor-arg name="connectionNum" value="666"/>
</bean>
<bean id="userDao" class="impl.UserDaoImpl"/>
<bean id="bookService" class="impl.BookServiceImpl">
<constructor-arg name="bookDao" ref="bookDao"/>
<constructor-arg name="userDao" ref="userDao"/>
</bean>
</beans>
说明:这两个<contructor-arg>
的配置顺序可以任意
上面已经完成了构造函数注入的基本使用,但是会存在一些问题:
当构造函数中方法的参数名发生变化后,配置文件中的name属性也需要跟着变,这两块存在紧耦合,具体该如何解决?
在解决这个问题之前,需要提前说明的是,这个参数名发生变化的情况并不多,所以上面的还是比较主流的配置方式,下面介绍的,大家都以了解为主。
优化方案一
删除name属性,添加type属性,按照类型注入
<bean id="bookDao" class="impl.BookDaoImpl">
<constructor-arg type="int" value="10"/>
<constructor-arg type="java.lang.String" value="mysql"/>
</bean>
- 这种方式可以解决构造函数形参名发生变化带来的耦合问题
- 但是如果构造方法参数中有类型相同的参数,这种方式就不太好实现了
优化方案二
删除type属性,添加index属性,按照索引下标注入,下标从0开始
<bean id="bookDao" class="impl.BookDaoImpl">
<constructor-arg index="1" value="100"/>
<constructor-arg index="0" value="mysql"/>
</bean>
- 这种方式可以解决参数类型重复问题
- 但是如果构造方法参数顺序发生变化后,这种方式又带来了耦合问题
依赖注入方式的选择
两种参数的注入方式,具体我们该如何选择呢?
强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
强制依赖指对象在创建的过程中必须要注入指定的参数
可选依赖使用setter注入进行,灵活性强
可选依赖指对象在创建过程中注入的参数可有可无
- Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
- 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- ==自己开发的模块推荐使用setter注入==
总结
setter注入
简单数据类型
<bean ...> <property name="" value=""/> </bean>
引用数据类型
<bean ...> <property name="" ref=""/> </bean>
构造器注入
简单数据类型
<bean ...> <constructor-arg name="" index="" type="" value=""/> </bean>
引用数据类型
<bean ...> <constructor-arg name="" index="" type="" ref=""/> </bean>
依赖注入的方式选择上
- 建议使用setter注入
- 第三方技术根据情况选择