理解spring ioc 原理

Ioc容器是Spring的核心,Spring的依赖反转由Ioc实现,同时,几乎其他所有的Spring特性都依赖Ioc容器。Ioc容器是Spring框架最核心的部分。

先说一段容器启动的Demo代码:

public class IocDemo {
    static AnnotationConfigApplicationContext annotationConfigApplicationContext;
    public static void main(String[] args) throws InterruptedException {
        annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.scan("com.tubemogul.springsecuredemo.springDemo.bean");
        annotationConfigApplicationContext.refresh();
        TestService2 testService2 = annotationConfigApplicationContext.getBean(TestService2.class);
        System.out.println(testService2.getClass().getName());
    }
}

这里选择的容器是AnnotationConfigApplicationContext,基于注解配置的(个人认为比XML好,依赖配置和代码在一起,一可以减少配置量,二也更直观)。在获取容器对象前有3步:
1. new出AnnotationConfigApplicationContext对象
2. 调用scan函数,扫描bean配置。
3. refresh完成容器初始化。

一. 理解AnnotationConfigApplicationContext对象

首先理解AnnotationConfigApplicationContext对象,除了这个以外,类似的还有XmlConfigApplicationContext对象等。Spring容器有很多种,应对不同的需求场景,容器的功能按接口进行逻辑拆分。这是Ioc容器接口设计图:
这里写图片描述

理解下几个顶层接口,BeanFactory接口包含对bean的操作,比如获取bean,Message接口包含消息类操作,ReasourceLoader负责资源加载,ApplicationEventPublisher包含应用程序事件发布功能。

这里可看出ioc容器的2大系列,beanFactory系列和applicationContext系列的关系,实际applicationContext系列容器是beanFactory容器系列的功能增强版,除了容器管理功能外,还增加了消息,资源加载,应用程序事件发布等功能。

那么看看我用的实现类AnnotationConfigApplicationContext的继承关系:
这里写图片描述

重点理解BeanFactory的功能,沿着继承树查看,getBean()方法是在AbstractApplicationContext类中实现:
这里写图片描述

这里调用getBeanFactory()获取BeanFactory,真实的BeanFactory封装在GenericApplicationContext,本质上是一个DefaultListableBeanFactory:
这里写图片描述
进入DefaultListableBeanFactory查看,这里就是实际持有Bean和BeanDefinition的地方

二. 理解AnnotationConfigApplicationContext对配置的加载

追踪annotationConfigApplicationContext.scan(“com.tubemogul.springsecuredemo.springDemo.bean”);方法,我们会来到ClassPathBeanDefinitionScanner类中的doScan方法:
这里写图片描述

从注释和代码上理解,这个方法就是根据入参的包地址扫描配置,并装配成一个BeanDefinition的集合,最后注册在registry中。AnnotationConfigApplicationContext是从代码注解中扫描配置装配出BeanDefinition(同理XmlConfigApplicationContext就是从XML文件中扫描装配出BeanDefinition)。看下BeanDefinition接口:
这里写图片描述

基本上涵盖了生成一个Bean需要的函数,可以理解Spring容器生成Bean就是基于BeanDefinition来生成的。

再说说最后的注册BeanDefinition到register对象中,这个register对象实际上就是AnnotationConfigApplicationContext,这类是实现了AnnotationConfigRegistry接口的
这里写图片描述

追踪register方法,其实是在AnnotationConfigApplicationContext持有的AnnotatedBeanDefinitionReader对象中实现的,这应该算是设计模式中的桥接模式。

这个代码其实写得有点绕,看AnnotatedBeanDefinitionReader的初始化:
这里写图片描述

看到没有,这里又把AnnotationConfigApplicationContext当成register给传进去了,追踪到AnnotatedBeanDefinitionReader里的regiseterBean方法:
这里写图片描述
最终调用了registry.registerBeanDefinition()方法完成了注册BeanDefinition的过程:
这里写图片描述

理解registry之前,理解一下为什么Spring作者要弄一个AnnotatedBeanDefinitionReader出来,我理解就是针对AnnotationConfig的一些专用处理的封装,在给真正registry注册BeanDefition之前,抽象了一层Reader,适配不同的配置源。

registerBeanDefinition其实是在DefaultListableBeanFactory中实现的,最终BeanDefinition是在DefaultListableBeanFactory的beanDefinitionMap中保存。至此,Scan()函数的工作就完成了,其实就是读取配置,解析配置,转换为BeanDefinition并保存。

三. refresh()方法完成Ioc容器初始化

AbstractApplicationContext.refresh()方法是在AbstractApplicationContext类中实现,直接看源码:
这里写图片描述

步骤很多,根据函数名和注释大致可以理解每一步是做什么的
调用过refresh函数后,就可以从容器中获取对象了。

最后可以看出来,其实读取配置的过程就是装配BeanDefinition并保存,在getBean的时候才会根据BeanDefinition生成时间Bean对象,当然如果是单例对象就会被缓存起来,生成对象时会连带注入依赖对象等等操作。

功能有多复杂,代码就有多复杂,Spring ioc细节很多,也不可能一一搞清楚,只有先了解大致原理,在具体使用中在根据需要选择性的深入

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值