ico源码分析:
-
IOC初始化,创建 Bean 容器
1:Resource定位:ClassPathReource resource = new ClassPathReource("bean.xml");
2:BeanDefinition的载入和解析: DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); , XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
3:BeanDefinition注册: reader.loadBeanDefinition(resource);
-
图解:
-
Reource定位
- 主要是两个接口:ResourceSpring中的统一资源抽象接口;ResourceLoader是统一的资源加载抽象接口
- 具体的方法实现我不会说,只需要知道接口的具体实现类会将外部的资源加载到Spring中,当然是以被封装的形式存在.(resource->EncodedResource).最后会以EncodedResource对象的形式用于bean的后续初始化.
-
BeanDefinition的载入和解析
- EncodedResource并不是直接就转换成BeanDefinition对象,而是要先转换成Document对象,然后再转换为BeanDefinition对象.这样做的原因也很简单,就是Document更方便.
- 从EncodedResource到Document的转换过程有很多细节(比如文件解析器,错误处理,命名空间的问题),这里暂时将这个过程看做黑盒.
- Document -> BeanDefinition的过程其实主要是和对Document的操作有关,也就是对xml标签的处理,有默认标签和自定义标签,不详细说.
-
注册BeanDefinition
- 其实就是一些Map,BeanDefinition作为value,key是beanName的map有存储BeanDefinition的Map,所谓注册,就是添加进入这个Map的过程,这里的key是beanName。
初始化的过程就是这样,用一张图结束吧:
-
Bean实例化
- 实例化时机分为很多种,一是使用BeanFactory和ApplicationContext的区别,二是Bean单例和多例的区别,三是单例情况下设置延迟加载的区别;如果是非延迟加载,那么会在容器启动时实例化bean.如果是延迟加载,那么Bean的加载就是第一次显示或隐式的调用getBean方法(该方法调用doGetBean方法),所以从这个方法开始:
- 1.转换beanName,因为getBean传入的name不一定是beanName,可能传入的是aliasName或FactoryBean
- 2.从缓存中获取bean,这里需要根据bean的作用域分一下情况:
- 单例:spring的IOC只会保存一个对象实例,所有该对象的引用都共享这个实例,Spring容器只会创建唯一一个实例,保存在缓存中,并对该bean的后续请求和引用都会返回到该缓存的对象实例中。
- 多例:每次对bean的请求都会返回一个新的实例
- 其他:
- request : 每次http请求都会有一个bean实例
- session: 一个session中,一个bean定义对应一个bean实例
- 所以,从缓存中获取的bean一定是单例的,这里的缓存也是一个Map,名为singletonObjects,同层次还有两个Map,一个是earlySingletonObjects,另一个是singletonFactories.分别保存早期单例对象和bean工厂.之所以使用三个缓存,是为了解决bean之间的循环依赖.
- 3.缓存中没有找到的话,会在父容器的缓存中寻找。
- 4.如果没有父容器或者父容器中也没有就会创建bean实例对象.这里的方法是createBean,如果createBean维持的一个缓存中没有对应bean的beanWrapper,这里会先创建BeanWrapper,这是一个对要实例化Bean的包装.创建BeanWrapper的方法是createBeanInstrance,同时,这个方法也是非单例bean的创建实例的方法.使用的就是初始化时创建的BeanDefinition,大致的步骤就是确定构造方法,然后实例化.实现起来有很多细节,比如如果有动态代理,就需要使用cglib来实例化,否则使用反射实例化。回到createBean方法,得到BeanWrapper对象后,就要进行一系列的处理,主要是属性注入和循环依赖的处理.然后初始化Bean。初始化Bean主要是为了完成用户设定,例如激活Aware方法,应用后置处理器方法,激活自定义的方法.
- 5.得到了bean实例,但是并没有结束,无论是从单例缓存中获取的或者createBean中创建的bean,都只是bean实例,还需要从bean实例中获取对象.这里很难理解,bean实例难道不是对象吗,我看的博客中都是这样说的,但是从我的理解来看,这里的bean实例其实是FactoryBean实例,不知道FactoryBean的可以了解一下.总之,最后需要从FactoryBean中拿到对象,其实就是调用了getObject方法,不过框架嘛,你懂得,总是需要处理很多情况,所以嵌套的比较深,可以从getObjectForBeanInstance和getObjectFromFactoryBean两个方法入手自己看一下。
-
推荐阅读: