IOC属于Spring的核心内容,如果想掌握好Spring你肯定需要对IOC有足够的了解 @mikechen
IOC的定义
IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”。
IOC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。
传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试,有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,如下图所示:
上图引入了IOC容器,使得A、B、C、D这4个对象没有了耦合关系,齿轮之间的传动全部依靠“第三方”了,全部对象的控制权全部上缴给“第三方”IOC容器。
所以,IOC借助于“第三方”实现具有依赖关系的对象之间的解耦,使程序更优良。
IOC与DI的关系
其实IOC包括依赖查找(DL)和依赖注入(DI),只不过DL因为有侵入性 (它需要用户自己去是使用 API 进行查找资源和组装对象),已经被抛弃。
所以现在提到IOC,更多的想到的就是依赖注入(DI)了,如图所示:
DI的全称是Dependency Injection,中文称之为依赖注入,它与控制反转(IOC)的含义相同,只不过这两个称呼是从两个角度描述的同一个概念。
当某个Java对象(调用者)需要调用另一个Java对象(被调用者,即被依赖对象)时,在传统模式下,调用者通常会采用“new 被调用者”的代码方式来创建对象,如图所示:
这种方式会导致调用者与被调用者之间的耦合性增加,不利于后期项目的升级和维护。
在使用Spring框架之后,对象的实例不再由调用者来创建,而是由Spring容器来创建,Spring容器会负责控制程序之间的关系,而不是由调用者的程序代码直接控制。
这样,控制权由应用代码转到了Spring容器,控制权发生了反转,这就是Spring的控制反转IOC。
从Spring容器的角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,这相当于为调用者注入了它依赖的实例,这就是Spring的依赖注入,如图所示:
依赖注入方式
Spring的依赖注入,我们一般使用@Autowired注解来完成,关于依赖注入一般有三种方式:
属性注入、构造器注入、setter方法注入:
1.属性注入
属性注入是大家最为常见也是使用最多的一种注入方式了,代码如下:
@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; //... }
2.Set注入
set 方法注入太过于臃肿,实际上很少使用:
@Service public class UserServiceImpl implements UserService { private UserMapper userMapper; @Autowired public void setUserMapper(UserMapper userMapper) { this.userMapper = userMapper; } }
3.构造器注入
构造器注入是官方推荐的方式,如下:
@Service public class UserServiceImpl implements UserService { private final UserMapper userMapper; @Autowired public UserServiceImpl(UserMapper userMapper) { this.userMapper = userMapper; } }
IOC的优缺点
IOC的优点
实现组件之间的解耦,提高程序的灵活性和可维护性。
IOC的缺点
使用IOC框架产品能够给我们的开发过程带来很大的好处,但是也要充分认识引入IOC框架的缺点,做到心中有数。
- 生成一个对象的步骤变复杂了(其实上操作上还是挺简单的),对于不习惯这种方式的人,会觉得有些别扭和不直观。
- 对象 生成因为是使用反射编程,在效率上有些损耗,但相对于IoC提高的维护性和灵活性来说,这点损耗是微不足道的,除非某对象的生成对效率要求特别高。
IOC的实现原理
IOC容器其实就是一个大工厂,它用来管理我们所有的对象以及依赖关系。
- 原理就是通过 Java 的反射技术来实现的,通过反射我们可以获取类的所有信息(成员变量、类名等等等);
- 再通过配置文件(xml)或者注解来描述类与类之间的关系。
这样我们就可以通过这些配置信息和反射技术来构建出对应的对象和依赖关系了,如下图所示:
IOC容器和对象的创建过程如下:
1.先创建BeanFactory容器
2.加载配置文件,封装成BeanDefinition
3.调用执行BeanFactoryPostprocessor
- 准备工作;
- 准备BeanPostProcessor;
- 准备监听器、事件、广播器;
4.实例化
5.初始化
6.获取到完整对象。
陈睿mikechen
10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!
后台回复【面试】即可获取《史上最全阿里Java面试题总结》,后台回复【架构】,即可获取《阿里架构师进阶专题全部合集》