1.IOC是什么
Inversion of Control,译为控制反转。
把复杂系统分解成相互合作的对象,这些对象类通过封装以后,内部实现对外部是透明的,从而降低了解决问题的复杂度,而且可以灵活地被重用和扩展。
将对象的创建权交给 Spring 去创建。 使用 Spring 之前,对象的创建都是由我们自己在代码中 new 创建。而使用 Spring 之后。对象的创建都是由给了 Spring 框架。
2.IOC原理
运用:把对象的创建和对象之间的调用过程,交给Spring管理
用一张网图来说明:
普通方式我们需要在UesrService类中调用uesrDao中add方法需要先在UesrService中new uesrDao的对象,再调用方法,耦合度太高;
于是用工厂模式来尽量降低他们的耦合度,在UserFactory中返回创建的对象,对象在工厂中得到。这个过程只是降低了UserService和UserDao的耦合度,没有降低到最大限度;
于是需要IOC来进一步降低耦合度。
3.IOC过程
3.1 配置xml文件,配置要创建的对象
<bean id="名字" class="路径"></bean>
3.2 创建工厂类
假如有上service类和dao类,创建工厂类
class UserFactory {
public static UserDao getDao() {
String classValue = class属性值; //通过xml解析得到class的值
//通过反射得到对象
Calss clazz = class.forName(classValue);
return (UserDao)clazz.newInstance(); //调用newInstance方法此时返回的也是UserDao对象
}
}
只要修改xml的配置文件,即可通过UserFactory工厂返回对象,耦合度进一步降低。
4.依赖注入(DI)
依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。通过将依赖对象注入到被依赖对象中,实现了对象之间的解耦和灵活性。
依赖的对象不需要手动调用 setXX 方法 去设置,而是通过配置赋值。
5.IOC总结
5.1 IOC本质是个容器,本质上是对象工厂,通过读取配置文件,再通过它用反射来完成
5.2 Spring提供的IOC容器的俩种实现方式(俩个接口)
- BeanFactory:IOC容器基本实现方式,Spring内部使用接口,一般不提供开发人员使用。
- 特点:加载配置文件,不会去创建对象。在获取或使用对象时才创建对象。
- ApplicationContext:可以理解成BeanFactory子接口,比BeanFactory更加强大。面向开发人员。
- 特点:加载配置文件,就会去创建对象。一般使用第二种。
5.3 示例:在Java中使用Spring Framework实现IOC:
- 定义一个接口
UserService
:
public interface UserService {
void saveUser(String username);
}
- 创建一个实现了
UserService
接口的类UserServiceImpl
:
public class UserServiceImpl implements UserService {
@Override
public void saveUser(String username) {
System.out.println("Saving user: " + username);
// 其他具体的业务逻辑...
}
}
- 配置 Spring 的 XML 配置文件
applicationContext.xml
,并在其中声明UserServiceImpl
作为一个 Bean:
<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="userService" class="com.example.UserServiceImpl" />
</beans>
- 创建一个主类
MainApp
,在其中使用 ApplicationContext 来获取UserService
Bean,并调用其方法:
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
public static void main(String[] args) {
// 加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取 UserService Bean
UserService userService = context.getBean(UserService.class);
// 调用方法
userService.saveUser("Mario");
}
}
IOC 优点 :
利用移动硬盘和电脑主机进行举例:
- 在插入主机之前,与电脑主机没有任何的关系,只有被我们连接在一起之后,两者才发生联系,具有相关性。所以,无论两者中的任何一方出现什么的问题,都不会影响另一方的运行。这种特性体现在软件工程中,就是可维护性比较好,非常便于进行单元测试,便于调试程序和诊断故障。代码中的每一个Class都可以单独测试,彼此之间互不影响,只要保证自身的功能无误即可,这就是组件之间低耦合或者无耦合带来的好处。
- 移动硬盘和电脑主机的之间无关性,还带来了另外一个好处,生产移动硬盘的厂商和生产电脑主机的厂商完全可以各干各事,他们之间唯一需要遵守的就是接口标准;
- 同一个移动硬盘设备可以插接到任何支持移动硬盘的设备,可以插接到不同的电脑主机,可以被反复利用。在软件工程中,这种特性就是可复用性好,我们可以把具有普遍性的常用组件独立出来,反复利用到项目中的其它部分,或者是其它项目,当然这也是面向对象的基本特征。
- 模块具有热插拔特性(系统运行过程中,能够动态地安装、卸载或替换硬件设备、软件模块或其他组件,而不需要重启整个系统或应用程序)。IOC生成对象的方式转为外置方式,也就是把对象生成放在配置文件里进行定义,这样,当我们更换一个实现子类将会变得很简单,只要修改配置文件就可以了,完全具有热插拨的特性。
IOC 缺点:
- 创建对象的步骤变复杂了,不直观
- 使用反射来创建对象,所以在效率上会有些损耗。但相对于程序的灵活性和可维护性来说,这点损耗是微不足道的。