前言
通过IOC控制反转的学习,我们已经知道了如果将类的创建进行控制反转,并使用Spring容器来管理;也知道了如何创建Spring容器,从中获取Bean。
但是当我们一个类中定义了其他基本类型或引用类型的属性,那么怎么在从Spring容器中获取Bean的同时,也能够让Bean中的属性赋上值呢?
这就是我们要学习的DI依赖注入。
依赖注入简介
当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。
但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。
简而言之,依赖注入就是在Spring容器中获取一个Bean的同时,让这个Bean中需要的属性、参数也能获取到对应的值。
依赖注入的方式
- 通过构造方法进行注入
- 通过set方法进行注入
DI入门案例
- 通过构造方式进行注入
- User实体类
/** * 用户实体类 */ public class User { private String name; //姓名 private int age; //年龄 public User(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
- applicationContext配置文件
<?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"> <!-- 配置User id:表示此bean的唯一标识 class:指定要创建对象的类的字节码对象 --> <bean id="user" class="com.itheima.entity.User"> <!-- 当通过构造方法注入时,使用constructor-arg标签 name:对应构造方法的参数 value:对name指定的参数进行赋值,无论字符和数字都用双引号 --> <constructor-arg name="name" value="张三"/> <constructor-arg name="age" value="25"/> </bean> </beans>
- 测试代码
public class Test { public static void main(String[] args) { //加载配置文件,创建Spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取Bean User user = context.getBean("user", User.class); System.out.println(user); } }
- 结果
- User实体类
- 通过set方法注入
- User1实体类
/** * 用户实体类 */ public class User1 { private String name; //姓名 private int age; //年龄 public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
- applicationContext.xml配置文件
<!-- 配置User1 id:表示此bean的唯一标识 class:指定要创建对象的类的字节码对象 --> <bean id="user1" class="com.itheima.entity.User1"> <!-- 当通过set方法注入时,使用property标签 name:对应set方法的方法名(例如setName方法,去掉setN -> 对应的是:name) value:对name指定的参数进行赋值,无论字符和数字都用双引号 --> <property name="name" value="李四"/> <property name="age" value="56"/> </bean>
- 测试类
public class Test1 { public static void main(String[] args) { //加载配置文件,创建Spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取Bean User1 user1 = context.getBean("user1", User1.class); System.out.println(user1); } }
- 结果
- User1实体类
多种类型依赖注入
属性类型分类
- 基本类型包装类,比如 Integer、Double、Boolean;
- 字符串类型,比如 String;
- 集合类型,比如 list、set、map 。
- 类类型,比如 其余定义的 java 类;
代码数据准备
//用户实体类
public class User {
private Integer id;
private String name;
private Object [] array;
private List list;
private Map map;
//省略get和set方法
}
以下根据这个实体类来演示各个属性类型的依赖注入。
基本类型和字符串类型
对于基本类型和字符串类型,在 xml 的配置文件中,通过 value 属性即可以赋值,在入门案例中已经使用。
数组类型
- 配置文件编写
<!-- 数组的属性注入 id:设置bean的唯一标识,获取Bean的时候根据id进行获取 class:要创建对象的类的字节码对象,对象创建后会由Spring进行管理 --> <bean id="user" class="com.offcn.entity.User"> <property name="array"> <array> <value>tom</value> <value>jerry</value> </array> </property> </bean>
- 配置解释
- property 中的 name Java类中数组的set方法的名字 如:SetArray 去掉Set ,A小写,得到array;name只与set方法有关。 property表示通过set方法注入。
- array 标签是固定的,不能变化,表示属性是一个数组,所以加在了 property 的属性内部。
- value 表示数组中的值,因为数组可以存储多个值,所以每一个数组的值,通过一个 value 标签声明。
集合类型
- list集合依赖注入
- 配置文件编写
<!-- 集合的属性注入 --> <bean id="user" class="com.offcn.entity.User"> <property name="list"> <list> <value>笑傲江湖</value> <value>侠客行</value> <value>连城诀</value> </list> </property> </bean>
- 配置解释
- property 中的 name 是 java 类中List集合的set方法名,表示通过set方法注入,name只与set方法名有关。
- list 标签是固定的,不能变化,表示属性是一个 list 集合 ,所以加在了 property 的属性内部
- value 表示集合中的值,因为集合可以存储多个值,所以每一个集合中的值,通过一个 value 标签声明.
- List集合与Set集合相同
- 配置文件编写
- map集合依赖注入
- 配置文件编写
<bean id="user" class="com.offcn.entity.User"> <property name="map"> <map> <entry key="小亮" value="小路"></entry> <entry key="文同学" value="伊利姐"></entry> </map> </property> </bean>
- 配置解释
- property 中的 name 是 java 类中List集合的set方法名,表示通过set方法注入,name只与set方法名有关。
- map 标签是固定的,不能变化,表示属性是一个 map 集合 ,所以加在了 property 的属性内部。
- entry 标签固定表示 map 中的一对键值对,map 也可以存储多对,所以 key 表示键值对的键,value 表示键值对的值。
- 配置文件编写
类类型
一个类中依赖另一个类的情况;就像我们编写三层架构的时候,表现层依赖业务逻辑层,业务逻辑层依赖数据访问层;只有数据访问层与数据库打交道。
以下我们就模拟一下 业务逻辑层依赖数据访问层的情况;也就是说在逻辑层中,有数据访问层类的成员变量属性。
数据准备
- 数据访问层 UserDao
/** * 模拟关于用户的数据访问层 */ public class UserDao { /** * 模拟保存用户 */ public void saveUser() { System.out.println("我是UserDao中的保存用户的方法!"); } }
- 业务逻辑层 UserService
/** * 模拟用户业务逻辑层 */ public class UserService { //依赖数据访问层 private UserDao userDao; //提供set方法,方便依赖注入 public void setUserDao(UserDao userDao) { this.userDao = userDao; } /** * 保存用户方法 */ public void saveUser() { //调用数据访问层的保存用户方法 userDao.saveUser(); } }
- 编写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" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd"> <!--先要配置数据访问层UserDao--> <bean id="userDao" class="com.my.Dao.UserDao"/> <!--配置业务逻辑层--> <bean id="userService" class="com.my.service.UserService"> <!-- 通过Set方法注入UserDao name:对应UserService类中的Set方法的名字 ref:(reference:引用),表示这个属性引用上面配置的UserDao的id,这样就能实现类类型的注入 --> <property name="userDao" ref="userDao"/> </bean> </beans>
- 配置说明
- property:表示通过Set方法进行依赖注入。
- name:对应UserService类中的Set方法的名字,name只与Set方法名相关。
- ref:表示这个属性引用上面配置的UserDao的id,这样就能实现类类型的注入,当我们从Spring中获取UserServices示例对象的时候,Spring会将UserServices对象依赖的UserDao实例对象,一并完成依赖注入。
- 测试代码
/** * 测试类 */ public class UserServiceTest { /** * 保存用户方法测试 */ @Test public void userSaveTest() { //创建spring容器,参数指定spring配置文件的全名 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //获取Bean UserService userService = context.getBean("userService", UserService.class); //调用保存用户方法 userService.saveUser(); } }
- 结果
总结
以上就是Spring的xml配置依赖注入的方式,在xml配置的时候一步一步来,看清楚一个类中依赖了哪些类,然后进行各个类的配置。