标签:conf single 线程 contain 等等 container 通过 过程 Servle
从最基础的Hello World开始。
spring的Hello World就三行代码:
public void test() { ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); SomeBean someBean= (SomeBean) context.getBean("someBean"); someBean.doSomething(); }
这个hello world非常简单,通过xml文件,创建一个容器context,然后从容器中获取一个bean。
运行完这段代码后,问自己两个问题:
虽然这个例子是用的xml配置,但是搞懂这两个问题,对于另外两种配置方式,注解配置和Java Config,也就顺理成章了,原理都一样的。
如何才能知道?调试。
好,开始回答第一个问题,容器创建时做了什么?
不管是xml,还是注解、Java Config,这些都是为了方便使用者而设计的,JVM可不知道说<bean>这个标签是啥意思,所以自然的,Spring需要对这些配置进行解析。
比如对于xml,就用XmlBeanDefinitionReader,把你写的beans.xml解析出来,你要创建什么对象,这些对象依赖哪些对象,是不是要懒加载(lazy-init),是不是单例...... 通通解析出来,放到一个叫BeanDefinition的对象里头,有多少种对象,就有多少个BeanDefinition,然后把这些BeanDefinition放到一个Map里头。
BeanDefinition有什么用?当然是为了后面实例化Bean用的,为什么要把配置信息放到BeanDefinition里?自然是不想每次需要实例对象时都去解析配置信息。
创建完所有BeanDefinition之后,会马上实例化对象吗?
如果用的是BeanFactory作为容器,则不会,对象默认都是懒加载,也就是在你想获取的时候再创建;
如果用的是上面hello world里的ApplicationContext ,则会马上实例化所有非懒加载的bean。
怎么实例化呢?这时候BeanDefinition就派上用场了,利用BeanDefinition里面的类信息,再用上反射,很容易就可以new出一个实例;
那如果bean里面依赖其他bean呢?那就顺带把其他bean也实例化出来,然后通过构造函数或者set方法,注入到bean里面去。
实例化后的bean,就直接返回给你了吗?这可不行,单例对象可是要复用的,Spring容器会被new出来的对象,放到又一个Map里面,这也解释了为什么bean不会被GC回收,因为bean通过Map和容器关联了,而容器对象是GC Root。当然,上面讲的仅限于单例,多例可不会放到Map里,容器创建完就直接丢出去了,让对象自生自灭,该回收时就回收。
第一个问题回答结束。
理解了第一个问题,第二个问题就很简单了,获取bean时又做了什么?
很简单:
第二个问题回答结束。
稍微总结一下。怎样读源码?先学会怎么用,再去弄懂为什么。知其然知其所以然,首先要知其然啊。
读源码跟读书很像的,带着疑问去阅读,效率会高很多
先粗读,也就是不断的单步调试,不必每个方法都step into想一看究竟,多step over,了解一下大概,然后记下疑问,进行第二版精读。
精读就要弄懂每一行代码吗?不必,只看你关心的,Spring IoC的实际逻辑比我上面讲的要复杂的多,包括一些如果放在bean在实例化的过程中,拒绝掉新的实例化请求等线程安全问题,这些都不是你关心的重点,看到了快速跳过即可,只看你关心的。
标签:conf single 线程 contain 等等 container 通过 过程 Servle
原文地址:https://www.cnblogs.com/myseries/p/10752763.html