作为Java程序员,依赖注入、控制反转这两个词汇几乎是必背的知识点。“注入”和“反转”使这两个词汇显得更加高级和动态。
首先我们看一下官方的解释:
控制反转
控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。
基本上官方的解释对于初学者来说,看和不看没什么区别。
控制反转:反转的是对象的创建过程。将对象被使用者创建改为框架自动创建。
依赖注入:由于对象交由框架创建,那么就需要拿到这个对象。
所以IOC框架主要就是关注对象的创建过程和使用过程。
对象的创建
- 首先执行new关键字后,虚拟机首先到方法区的常量池中查找是否有该类的符号引用。并判断是否被加载、解析和初始化。
- 如果没有,则执行类加载。
- 在java heap中分配内存。为保证线程安全,通常由该线程提前在堆中分配内存。
- 设置对象的头信息。
- 对对象的变量执行初始化操作。
- 内存图
Student s = new Student();
如果我们new一个对象,首先会在栈里面声明一个引用变量。而这个对象具体占用的内存会在堆内存中进行分配。而这个引用变量指向堆内存中对应的地址。这样只要我们使用变量s, 其实就是间接的访问了堆内存中对应的数据。
那为什么要把new 对象这个过程改成框架来完成呢?
如果我们频繁的创建这个对象,那么就会使用很多堆内存存放对象实例。如果对象没有自己的数据属性,也就是线程安全的。那么这些对象其实是一模一样的。那为什么不复用同一个对象呢?(也就是单例模式)
于是我们会用一个容器把所有可能会被复用的对象都放在一起,可以想成这个容器就是一个map,key是对象的名称,value就是对象实例的地址。于是我们就可以从这个容器中,取出我们想要的对象。因为复用对象,也可以占用更少的内存。
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-beans.xml");
Teacher teacher = applicationContext.getBean(Teacher.class);
Student student = (Student) applicationContext.getBean("student");
我们可以通过对象类型或者名称获取到对应的bean。就类似于@Autowied和@Resource。
@Autowied通过类型注入。
@Resource通过名称注入。
而所谓的注入,就是将我们声明的引用变量关联上堆内存中对象的内存地址。
因此: