SpringDI(依赖注入)
DI 概述
Dependency Injection
即为依赖注入,简称 DI 。
简单来说,在 Spring 创建对象的同时,为其属性赋值,称之为依赖注入。
形象来说,组件之间依赖关系由容器在运行期决定的,即由容器动态的将某个依赖关系注入到组件之中。
什么是 DI
了解 DI 的思想
简单了解了 DI(依赖注入),在看依赖注入这个词,我们也可以将依赖注入以 IOC(控制反转)的形式拆分它。
顾名思义,依赖注入是由“依赖”和“注入”两个词汇组合而成,那么我们再一次顺藤摸瓜,分别分析这两个词语!
依赖
依赖一词,可以拆分成很多元素。比如说,达成依赖条件必须是两个对象 ,谁依赖谁 ,某一个对象依赖另一个对象的什么 。这里我们可以根据这几个条件列举出这几种情况:
- 关于谁依赖与谁,当然是应用程序依赖于 IOC 容器。因为应用程序依赖于 IOC 容器提供的对象所需外部资源,所以就产生了这种依赖关系。(可以理解为入口,虽然不是这么严谨吧!)
注入
注入一次,可以也可以拆分成很多元素。比如说,注入可以分解成谁注入谁 ,注入了什么 。这里我们也可以根据这两个条件来列举出这几种情况:
- 关于谁注入谁,身为容器的 IOC 肯定是被注入的对象,也就是说我们将所需要的对象注入到 IOC 容器中。至于注入了什么,很明显,就是我们项目中所需要的对象、资源、数据等等。简单来说,我们需要外部的资源既可以注入到 IOC 容器中,并由 IOC 容器来实现注入对象的控制反转!
- IOC 的是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过 DI(Dependency Injection,依赖注入)来实现的。
注入方式
Setter 方法注入
Setter 方法注入,它只需要提供对应的 Setter 方法接口实现注入,由于 JavaBean 一般都实现了 Setter 方法,所以 Setter 方法注入也成为了我们常用的注入方法之一。
定义 JavaBean
定义一个 JavaBean 并赋予其 Setter 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.mylifes1110.bean;
import java.util.*;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @AllArgsConstructor @NoArgsConstructor public class User { private Integer id; private String password; private String sex; private Integer age; private Date bornDate; private String[] hobbys; private Set<String> phones; private List<String> names; private Map<String, String> countries; private Properties files; }
|
注入各种数据类型
注意:Spring 底层对 Date 日期类型做了处理,默认处理格式为“yyyy/MM/dd”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| <bean id="User" class="com.mylifes1110.bean.User"> <property name="id" value="1"/> <property name="password" value="123456"/> <property name="sex" value="male"/> <property name="age" value="18"/> <property name="bornDate" value="1999/09/09"/> <property name="hobbys"> <array> <value>Run</value> <value>Jump</value> <value>Climb</value> </array> </property> <property name="names"> <list> <value>Ziph</value> <value>Join</value> <value>Marry</value> </list> </property> <property name="phones"> <set> <value>110</value> <value>119</value> <value>120</value> </set> </property> <property name="files"> <props> <prop key="first">One</prop> <prop key="second">Two</prop> <prop key="third">Three</prop> </props> </property> <property name="countries"> <map> <entry key="CHINA" value="中国"/> <entry key="USA" value="美国"/> <entry key="UK" value="英国"/> </map> </property> </bean>
|
注入自建类型数据
将 Service 层需要一个 Dao 层实现类对象,我们可以使用注入方式来实现对 Service 层和 Dao 层的对象关联
1 2 3 4
| <bean id="UserDao" class="com.mylifes1110.dao.impl.UserDaoImpl"/> <bean id="UserService" class="com.mylifes1110.service.impl.UserServiceImpl"> <property name="userDao" ref="UserDao"/> </bean>
|
将创建的 Bean 对象注入到另一个对象中,比如一个 JavaBean 对象中作为了另一个 JavaBean 对象的属性
1 2 3 4 5 6 7 8 9 10 11
| <bean id="address" class="com.mylifes1110.bean.Address"> <property name="position" value="上海市" /> <property name="zipCode" value="100001" /> </bean>
<bean id="user" class="com.mylifes1110.bean.User"> <property name="address" ref="address" /> </bean>
|
构造方法注入
创建对象时,Spring 工厂会通过构造方法为对象的属性赋值。由于某些框架或者项目中并没有为 JavaBean 提供 Setter 方法,我们就可以利用其构造方法来注入。不要和我说,没有提供构造方法哈!(开个玩笑!)
定义 JavaBean
定义一个 JavaBean 对象,为其提供构造方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class Student { private Integer id; private String name; private String sex; private Integer age;
public Student(Integer id , String name , String sex , Integer age){ this.id = id; this.name = name; this.sex = sex; this.age = age; } }
|
构造方法注入
1 2 3 4 5 6 7 8
| <bean id="u3" class="com.mylifes1110.bean.Student"> <constructor-arg name="id" value="1234" /> <constructor-arg name="name" value="tom" /> <constructor-arg name="age" value="20" /> <constructor-arg name="sex" value="male" /> </bean>
|
自动注入
不用在配置中 指定为哪个属性赋值,及赋什么值。由 spring 自动根据某个 “原则” ,在工厂中查找一个 bean,为属性注入属性值。
注入场景
将 Dao 层实现类对象注入到 Service 层并调用方法得以测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.mylifes1110.service.impl;
import com.mylifes1110.bean.User; import com.mylifes1110.dao.UserDao; import com.mylifes1110.service.UserService;
public class UserServiceImpl implements UserService { private UserDao userDao;
public void setUserDao(UserDao userDao) { this.userDao = userDao; }
@Override public int insertUser(User user) { System.out.println("------insertUser and UserService------"); return userDao.insertUser(null); } }
|
自动注入的两种方式
基于名称自动注入值
1 2 3 4
| <bean id="UserDao" class="com.mylifes1110.dao.impl.UserDaoImpl"/> <bean id="userService" class="com.mylifes1110.service.impl.userServiceImpl" autowire="byName"/> </beans>
|
基于类型自动注入值,根据实现的接口来判断并自动注入值,如果实现此接口的实现类太多,它会在很多实现此接口的实现类中选择名字相同的实现类进行注入。(现根据判断,如果不成功,则根据名称注入)
1 2 3 4
| <bean id="userDao" class="com.mylifes1110.dao.UserDaoImpl" /> <bean id="userService" class="com.mylifes1110.service.impl.UserServiceImpl" autowire="byType"/> </beans>
|
注解自动注入
注解名称 | 描述 |
---|
@Autowired | 基于类型自动注入 |
@Resource | 基于名称自动注入 |
@Qualifier(“userDAO”) | 限定要自动注入的 bean 的 id,一般和@Autowired 联用 |
@Value | 注入简单类型数据 (jdk8 种基本数据类型+String 类型) |
使用基于类型自动注入,将 Dao 层注入到 Service 层
1 2 3 4 5 6
| @Service public class UserServiceImpl implements UserService { @Autowired @Qualifier("userDao") private UserDao userDao; }
|
使用基于名称自动注入,将 Dao 层注入到 Serivce 层
1 2 3 4 5 6
| @Service public class UserServiceImpl implements UserService { @Resource("userDao") private UserDao userDao; }
|
使用注入简单类型数据注解来完成简单注入 JavaBean
1 2 3 4 5 6
| public class User{ @Value("1") private Integer id; @Value("Ziph") private String name; }
|