如何阅读spring源码

从最基础的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。

运行完这段代码后,问自己两个问题:

  • 容器创建时做了什么?
  • getBean()时又做了什么?

虽然这个例子是用的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时又做了什么?

很简单:

  • 如果bean是单例,并且还没实例化,那就按照上面的流程new一个,如果已经实例化了,就直接返回;
  • 如果是多例,new一个返回

第二个问题回答结束。

转载自:
作者:柳树
链接:https://www.zhihu.com/question/21346206/answer/359268420
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值