基于Spring为我们提供了两种注入方式,分别是:
- setter注入
- 简单类型
- 引用类型
- 构造器注入
- 简单类型
- 引用类型
1. 环境准备
构造器注入也就是构造方法注入,先准备下环境:
- 创建一个Maven项目
- pom.xml添加依赖
- resources下添加spring的配置文件
项目的结构如下:
(1)项目中添加UserDao、UserDaoImpl、CityDao、CityDaoImpl、UserService和UserServiceImpl类
public interface UserDao {
public void selcet();
}
public class UserDaoImpl implements UserDao {
private String userName;
private Integer userAge;
public void selcet() {
System.out.println("UserDao select, running ......");
}
}
public interface CityDao {
public void select();
}
public class CityDaoImpl implements CityDao {
public void select() {
System.out.println("CityDao select, running ......");
}
}
public interface UserService {
public void userFromCity();
}
public class UserServiceImpl implements UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void userFromCity() {
System.out.println("UserService userFromCity, running .....");
userDao.selcet();
}
}
(2)resources下提供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="userDao" class="com.dcxuexi.dao.impl.UserDaoImpl" />
<bean id="userService" class="com.dcxuexi.service.impl.UserServiceImpl" >
<property name="userDao" ref="userDao" />
</bean>
</beans>
(3)编写SpringContructer运行类,加载Spring的IOC容器,并从中获取对应的bean对象
public class SpringContructer {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) context.getBean("userService");
userService.userFromCity();
}
}
2. 构造器注入引用数据类型
接下来,在上面这个环境中来完成构造器注入:
需求:将UserServiceImpl类中的userDao修改成使用构造器的方式注入。
1.将userDao的setter方法删除掉
2.添加带有userDao参数的构造方法
3.在applicationContext.xml中配置
步骤1:删除setter方法并提供构造方法
在UserServiceImpl类中将userDao的setter方法删除掉,并添加带有userDao参数的构造方法
public class UserServiceImpl implements UserService {
private UserDao userDao;
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao;
}
public void userFromCity() {
System.out.println("UserService userFromCity, running .....");
userDao.selcet();
}
}
步骤2:配置文件中进行配置构造方式注入
在applicationContext.xml中配置
<?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="userDao" class="com.dcxuexi.dao.impl.UserDaoImpl" />
<bean id="userService" class="com.dcxuexi.service.impl.UserServiceImpl" >
<!-- <property name="userDao" ref="userDao" />-->
<constructor-arg name="userDao" ref="userDao" />
</bean>
</beans>
说明:
标签<constructor-arg>
中
- name属性对应的值为构造函数中方法形参的参数名,必须要保持一致。
- ref属性指向的是spring的IOC容器中其他bean对象。
步骤3:运行程序
运行SpringContructer类,查看结果,说明userDao已经成功注入。
3. 构造器注入多个引用数据类型
需求:在UserServiceImpl使用构造函数注入多个引用数据类型,比如cityDao
1.声明cityDao属性
2.生成一个带有cityDao和userDao参数的构造函数
3.在applicationContext.xml中配置注入
步骤1:提供多个属性的构造函数
在UserServiceImpl声明userDao并提供多个参数的构造函数
public class UserServiceImpl implements UserService {
private UserDao userDao;
private CityDao cityDao;
public UserServiceImpl(UserDao userDao,CityDao cityDao) {
this.userDao = userDao;
this.cityDao = cityDao;
}
public void userFromCity() {
System.out.println("UserService userFromCity, running .....");
userDao.selcet();
cityDao.select();
}
}
步骤2:配置文件中配置多参数注入
在applicationContext.xml中配置注入
<?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="userDao" class="com.dcxuexi.dao.impl.UserDaoImpl" />
<bean id="cityDao" class="com.dcxuexi.dao.impl.CityDaoImpl" />
<bean id="userService" class="com.dcxuexi.service.impl.UserServiceImpl" >
<!-- <property name="userDao" ref="userDao" />-->
<constructor-arg name="userDao" ref="userDao" />
<constructor-arg name="cityDao" ref="cityDao" />
</bean>
</beans>
**说明:**这两个<contructor-arg>
的配置顺序可以任意
步骤3:运行程序
运行SpringContructer类,查看结果,说明userDao已经成功注入。
4. 构造器注入多个简单数据类型
需求:在UserDaoImpl中,使用构造函数注入userName和userAge两个参数。
参考引用数据类型的注入,我们可以推出具体的步骤为:
1.提供一个包含这两个参数的构造方法
2.在applicationContext.xml中进行注入配置
步骤1:添加多个简单属性并提供构造方法
修改UserDaoImpl类,添加构造方法
public class UserDaoImpl implements UserDao {
private String userName;
private Integer userAge;
public UserDaoImpl(String userName, Integer userAge) {
this.userName = userName;
this.userAge = userAge;
}
public void selcet() {
System.out.println("UserDao select, running ......");
System.out.println("userName = " +userName+" , userAge = " + userAge);
}
}
步骤2:配置完成多个属性构造器注入
在applicationContext.xml中进行注入配置
<?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="userDao" class="com.dcxuexi.dao.impl.UserDaoImpl" >
<constructor-arg name="userName" value="xiaoChuang" />
<constructor-arg name="userAge" value="24" />
</bean>
<bean id="cityDao" class="com.dcxuexi.dao.impl.CityDaoImpl" />
<bean id="userService" class="com.dcxuexi.service.impl.UserServiceImpl" >
<!-- <property name="userDao" ref="userDao" />-->
<constructor-arg name="userDao" ref="userDao" />
<constructor-arg name="cityDao" ref="cityDao" />
</bean>
</beans>
**说明:**这两个<contructor-arg>
的配置顺序可以任意
步骤3:运行程序
运行SpringContructer类,查看结果
上面已经完成了构造函数注入的基本使用,但是会存在一些问题:
- 当构造函数中方法的参数名发生变化后,配置文件中的name属性也需要跟着变
- 这两块存在紧耦合,具体该如何解决?
在解决这个问题之前,需要提前说明的是,这个参数名发生变化的情况并不多,所以上面的还是比较主流的配置方式,下面介绍的,大家都以了解为主。
方式一:删除name属性,添加type属性,按照类型注入
<bean id="userDao" class="com.dcxuexi.dao.impl.UserDaoImpl" >
<constructor-arg type="java.lang.String" value="xiaoChuang" />
<constructor-arg type="java.lang.Integer" value="24" />
</bean>
- 这种方式可以解决构造函数形参名发生变化带来的耦合问题
- 但是如果构造方法参数中有类型相同的参数,这种方式就不太好实现了
方式二:删除type属性,添加index属性,按照索引下标注入,下标从0开始
<bean id="userDao" class="com.dcxuexi.dao.impl.UserDaoImpl" >
<constructor-arg index="0" value="xiaoChuang" />
<constructor-arg index="1" value="24" />
</bean>
- 这种方式可以解决参数类型重复问题
- 但是如果构造方法参数顺序发生变化后,这种方式又带来了耦合问题
介绍完两种参数的注入方式,具体我们该如何选择呢?
- 强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
- 强制依赖指对象在创建的过程中必须要注入指定的参数
- 可选依赖使用setter注入进行,灵活性强
- 可选依赖指对象在创建过程中注入的参数可有可无
- Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
- 如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
- 实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
- 自己开发的模块推荐使用setter注入
主要介绍的是Spring的依赖注入的实现方式:
- 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注入
- 第三方技术根据情况选择