控制反转的一种实现方式——依赖注入
- 一、IoC 控制反转(Overview)
- 依赖注入(DI)- Overview
- 利用 IoC(控制反转)这种思想有什么好处呢?
- 二、依赖注入的方式
- setter 方式(xml配置中的property标签)
- 内部Bean和外部Bean
- 构造方式(xml配置中的constructor-arg标签)
一、IoC 控制反转(Overview)
- 控制反转是一种设计思想,也是Spring框架的核心。反转即是指本来由用户管理的
Bean对象
,现在由框架对其进行管理。 - 既然交给了 Spring框架 去管理,那除了负责实例化之外,当然也负责其
Bean对象
的生命周期
。 - 既然是管理
Bean对象
,那创建完之后放哪托管呢?IoC 容器。 - 既然是设计思想,那其实现方式呢?依赖注入(DI)是其一种实现方式。
有反转就有正转,正转就是指由用户去创建对象,就是去 new 啦。
依赖注入(DI)- Overview
应用程序从
IoC Container
中获取依赖的 Bean,注入到依赖的程序中,这个过程称为依赖注入(Dependency Injection,DI) 。 所以说控制反转是通过依赖注入实现的,其实它们是同一个概念的不同角度描述。通俗来说就是IoC是设计思想,DI是实现方式。
依赖注入常见的方式:
- 构造注入
- set 注入
利用 IoC(控制反转)这种思想有什么好处呢?
- 降低了程序的耦合度,提高了其扩展力;
- 达成了软件设计的七大原则中的俩:OCP(Open Close Principle)开放关闭原则:类、方法等对外开放,修改对外关闭;DIP(Dependency Inversion Principle)依赖倒置原则:通过抽象使各个类或者模块不相互影响,实现松耦合。
有关七大软件设计原则的详细介绍可以看这篇博客:
软件设计的七大原则
二、依赖注入的方式
构造方法注入、set 注入
IoC 有三种配置方式:xml配置、Java配置、注解配置。
setter 方式(xml配置中的property标签)
- 在xml配置中,利用
property
标签实现 setter 方式注入,具体实现:
<?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">
<!--配置dao-->
<bean id="userDaoBean" class="com.ncpowernode.spring6.dao.UserDao"/>
<!--配置service-->
<bean id="userServiceBean" class="com.ncpowernode.spring6.service.UserService">
<!--想让Spring 调用对应的set 方法,需要配置property 标签-->
<!--name 属性怎么指定值:set 方法的方法名,去掉set,然后把剩下的单词首字母编小写,写到这里-->
<!--ref 翻译为引用,英语单词:references,ref后面指定的是bean 的id-->
<!--set方法起名的时候,不要为难自己,遵循Bean规范,所以name位置写属性名就可以了-->
<property name="userDao" ref="userDaoBean"/>
</bean>
</beans>
-
property 标签
name
属性值是 set方法名去掉set,然后把剩下的第一个字符改为小写,其余不变的字符串。 -
ref
属性值是 IoC容器中所对应的Bean对象的 Id
。
内部Bean和外部Bean
这里在 property
中使用了 ref
属性值去指明注入的对象,这种方式属于外部Bean
。
以下方式就是利用内部Bean
(就是property标签下利用bean子标签):
<property name="userDao">
<bean class="com.ncpowernode.spring6.dao.UserDao"/>
</property>
- UserDao 类中封装内容:
- UserService 类中封装的业务内容
- 测试:
构造方式(xml配置中的constructor-arg标签)
- 在 xml 配置中,在
constructor-arg
标签下配置要注入的对象,具体如下:
<?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="vipDaoBean" class="com.ncpowernode.spring6.dao.VipDao"/>
<bean id="vipServiceBean" class="com.ncpowernode.spring6.service.VipService">
<!--构造注入-->
<!--
index 属性指定参数下标,第一个参数是0,第二个参数是1,以此类推
ref 属性用来指定注入的bean 的id
-->
<!--指定构造方法的第一个参数,下标是0-->
<!--<constructor-arg index="0" ref="vipDaoBean"/>-->
<!--根据参数的名字-->
<constructor-arg name="vipDao" ref="vipDaoBean"/>
</bean>
</beans>
- VipDao 类的封装内容
public class VipDao {
private final Logger logger = LoggerFactory.getLogger(VipDao.class);
public void insert(){
logger.info("VipDao正在保存数据");
}
}
- VipService 类的封装业务内容
public class VipService {
private VipDao vipDao;
public VipService(VipDao vipDao){
this.vipDao = vipDao;
}
public void save(){
vipDao.insert();
}
}
测试: