往期文章:
一、IoC是什么
Ioc—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
谁控制谁,控制什么
传统Java SE程序设计,我们直接在对象内部通过new进行创建对象,是程序主动去创建依赖对象;而IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建;谁控制谁?当然是IoC
容器控制了对象;控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。为何是反转,哪些方面反转了
有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
二、IoC案例引入
① 我们先写一个UserDao接口
public interface UserDao {
public void getUser();
}
② 再写UserDao的实现类-UserDaoImpl
public class UserDaoImpl implements UserDao {
@Override
public void getUser() {
System.out.println("获取用户数据...");
}
}
③ 写一个UserService接口
public interface UserService {
public void getUser();
}
④ 最后写一个UserService的实现类-UserServiceImpl
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
⑤ 现在来获取用户数据吧
@Test
public void testGetUser(){
UserService userService = new UserServiceImpl();
userService .getUser();
}
这也是大家惯用的方式,现在我们对其做出一些修改。
将UserDao的实现类增加一个
public class UserDaoMySqlImpl implements UserDao {
@Override
public void getUser() {
System.out.println("MySql获取用户数据...");
}
}
紧接着我们要去使用MySql的话 , 我们就需要去service实现类里面修改对应的实现
public class UserServiceImpl implements UserService {
private UserDao userDao = new UserDaoMySqlImpl();
@Override
public void getUser() {
userDao.getUser();
}
}
如果我们再增加一个UserDao的实现类,使用oracle存储数据,那么我们又要去UserService
类里更改对应实例的获取。在开发中,这种需求是非常大的 ,因此我们惯用的方式有点不适用了, 甚至反人类。 每次变动 , 都需要修改大量代码 , 这种设计的耦合性太高, 牵一发而动全身 。
解决方案
我们可以在需要用到某个实例的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 。
public class UserServiceImpl implements UserService {
private UserDao userDao;
// 利用set实现
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
@Override
public void getUser() {
userDao.getUser();
}
}
这样一来,他们已经发生了根本性的变化,很多地方都不一样了。仔细去思考一下,以前所有东西都是由程序去进行控制创建, 而现在是由我们自行控制创建对象,把主动权交给了调用者。 程序不用去管怎么创建,怎么实现了。它只负责提供一个接口。
这种思想, 从本质上解决了问题,我们程序员不再去管理对象的创建了, 更多的去关注业务的实现。耦合性大大降低。这也就是IOC的原型 !
三、IoC与DI
控制反转IoC(Inversion of Control),是一种设计思想
,DI(依赖注入)是实现IoC的一种方法
。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,耦合性极高。但控制反转后将对象的创建转移给第三方,降低了程序间的耦合性,在我看来,控制反转就是获得依赖对象的方式反转了。
IoC是Spring框架的核心内容,使用多种方式完美的实现了IoC,可以使用XML配置,也可以使用注解,以及可以基于Java配置类实现完全脱离xml配置文件实现IoC。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(DependencyInjection,DI)。
四、 Spring中的IoC与DI
回到上述案例,我们最终用setter方法解决了程序的耦合性,在Spring中,我们只需在Spring核心配置文件中使用<bean>
标签注册每一个类,标签里添加对应属性,就可以实现对象的创建。
<?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="mysqlUserDao" class="com.tyt.dao.impl.UserDaoMySqlImpl"/>
<bean id="oracleUserDao" class="com.tyt.dao.impl.UserDaoOracleImpl"/>
<bean id="userService" class="com.tyt.service.impl.UserServiceImpl">
<!--引用 UserDaoMySqlImpl-->
<property name="userDao" ref="mysqlUserDao"/>
<!--如果想引用 UserDaoOracleImpl,只需将代码改为这一句-->
<!--
<property name="userDao" ref="oracleUserDao"/>
-->
</bean>
</beans>
测试:
public void test(){
ApplicationContext app= new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService )app.getBean("userService");
userService.getUser();
}
- UserService 对象是谁创建的 ?
UserService 对象是由Spring创建的
- UserService 对象的属性是怎么设置的 ?
UserService 对象的属性是由Spring容器设置的
对象已经转交给Spring控制了,这就叫控制反转;属性的设置也交给Spring设置了,这就是依赖注入
- 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 ;使用Spring后 , 对象是由Spring来创建的
- 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .
- 依赖注入 : 就是利用set方法来进行注入的.
下期文章: