小弟即将辞掉第一份工作,复习的时候问了我老大一句到底该怎么去理解Spring IOC呢?老大滔滔不绝的给我讲了一个多小时,我得到了一些启发,所以写下这篇文章,来记录我此次的收获。学习一样东西不要只学他做了什么,ioc是控制反转,但我们在认真的思考一下,出现这种特性,肯定是因为需求来的,从他的来龙去脉了解起,才能很好的建立自己的知识金字塔--来自我老大的原话。学习不是一蹴而就,学习是一个过程,送给各位朋友自勉。
1.IOC干了什么?
在我问我老大ioc的时候,抛出了第一个问题:如果现在没有IOC,那我们的Springboot要怎么写代码呢?那不是要疯狂new对象,从java内存的角度来看,new 对象有什么问题?对于一百个请求来说,如果都是new对象出来,那么对于某个controller的要调用的某个service来说,则需要new 100次。但事实上,我们都知道对于Spring ioc来说,service通过加了@Service注解后,在Spring启动时,通过@ComponentScan,扫描所有使用该注解的bean,并在beanFactory里面创建,默认创建的是单例模式,如图1.
在这张图里面,我们看到创建了一个testService,内容很简单只是打印一句话,然后在Application启动的时候,我们写了两个启动时执行特定方法的类来调用testservice的方法,不难发现testService指向的地址是同一个,也就是说在启动时,扫描完成后,添加了一个单例的testservice到bean工厂。
下面,我开始从jvm的内存模型去看按照ioc的设计思想,是怎么去做的,如图2(图2是我画的关于JVM的内存模型简易图),如果对jvm内存模型不了解的同学请自己先去了解一下哦,本篇文章不介绍jvm内存模型。
对着上面的图,在java编译的时候,testservice的类的信息和方法。一般情况,创建的对象都存在于堆里面,那么结合ioc(反转控制),如果在没有ioc的情况下,当一个请求过来的时候就会在堆里面创建一个testService对象,然而当调用testService的方法时候,发现方法早已在编译已经记录在方法区里面,调用时只是将方法区testService的方法复制过来,然后将线程内存里面虚拟机栈存储的局部变量填充调用而已,实在不需要创建这么多的对象。于是乎,Spring才想出了ioc的方法,将一些不太需要每次都创建对象的bean交给spring去处理。比如说,像testService这种bean对象,在spring启动时,交给bean工厂去处理,创建一个单例模式(默认是单例)对象,供使用者使用,减轻了内存的负担的同时,实现了这部分对象的解耦。
所以看到这里,应该明白了ioc存在的意义。