目录
ioc体系概述
BeanFactory 概述
基础类型IoC容器,提供完整的IoC服务支持。如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需要的资源有限。对于资源有限,并且功能要求不是很严格的场景,BeanFactory是比较合适的IoC容器选择。
ApplicationContext 概述
ApplicationContext在BeanFactory的基础上构建,是相对比较高级的容器实现,除了拥有BeanFactory的所有支持,ApplicationContext还提供了其他高级特性,比如事件发布、国际化信息支持等,ApplicationContext所管理的对象,在该类型容器启动之后,默认全部初始化并绑定完成。所以,相对于BeanFactory来说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容器启动时间较之BeanFactory也会长一些。在那些系统资源充足,并且要求更多功能的场中,ApplicationContext类型的容器是比较合适的选择。
几个重要的接口(类)
ListableBeanFactory(interface)
java-doc的描述:
- 获取所有的bean实例,而非一个一个按照名字等获取.如果
BeanFactory
实现了预加载所有的bean,可能会继承这个接口 - 如果实现了
hierarchialBeanFactory
,那么在当前工厂中,返回值不考虑分级,使用BeanFactoryUtils
帮助类获取祖先工厂的beans
, - 此接口只考虑当前工厂实现的
beans
,会忽略那些singleton-bean
,如ConfigurableBeanFactory
的registerSingleton
注册的单例bean.(getBeanNamesOfType,getBeansOfType会考虑手动注册的singletion-beans),beanFactory的getBean同样可以透明的访问这些特殊bean.在典型情况下,所有的bean都是由external bean定义,所以应用不需要顾虑这些差别. - 注意:
getBeanDefinitionCount
和containsBeanDefinition
的实现方法因为效率比较低,还是少用为好.
它可以枚举所有的bean实例,而不是客户端通过名称一个一个的查询得出所有的实例。要预加载所有的bean定义的beanfactory可以实现这个接口来。该接口定义了访问容器中Bean基本信息的若干方法,如查看Bean的个数、获取某一类型Bean的配置名、查看容器中是否包括某一Bean等方法.
1 | //是否包含bean |
HierarchicalBeanFactory
提供父容器的访问功能.至于父容器的设置,需要找ConfigurableBeanFactory的setParentBeanFactory(接口把设置跟获取给拆开了!).
1 | // 获取父容器 bean factory |
AutowireCapableBeanFactory
对于想要拥有自动装配能力,并且想把这种能力暴露给外部应用的BeanFactory类需要实现此接口。
正常情况下,不要使用此接口,应该更倾向于使用BeanFactory或者ListableBeanFactory接口。此接口主要是针对框架之外,没有向Spring托管Bean的应用。通过暴露此功能,Spring框架之外的程序,具有自动装配等Spring的功能。
需要注意的是,ApplicationContext接口并没有实现此接口,因为应用代码很少用到此功能,如果确实需要的话,可以调用ApplicationContext的getAutowireCapableBeanFactory方法,来获取此接口的实例。
如果一个类实现了此接口,那么很大程度上它还需要实现BeanFactoryAware接口。它可以在应用上下文中返回BeanFactory。
ConfigurableListableBeanFactory
提供bean definition的解析,注册功能,再对单例来个预加载(解决循环依赖问题).
貌似我们一般开发就会直接定义这么个接口了事.而不是像Spring这样先根据使用情况细分那么多,到这边再合并
设置忽略的依赖关系,注册找到的特殊依赖
1 | void ignoreDependencyType(Class<?> type); // 忽略类型 |
获取bean定义 (可以访问属性值跟构造方法的参数值)
1 | BeanDefinition getBeanDefinition(String beanName) |
锁定配置信息.在调用refresh时会使用到.
1 | //冻结全部bean定义 |
预加载不是懒加载的单例.用于解决循环依赖问题
1 | void preInstantiateSingletons() throws BeansException; |
ApplicationContext 初始化过程源码阅读
概述
简单来说,IoC容器的初始化是由refresh()
方法来启动的
这个启动包括BeanDefinition
的Resource
定位、载入和注册.
spring将这三个过程分开,使用不同的模块来完成,如使用ResourceLoader
、BeanDefinitionReader
等,可以让用户更灵活的对三个过程进行修改,定义出最适合自己的IoC容器的初始化过程
- 第一个过程是
Resource
定位过程(指BeanDefinition
)资源定位。由ResourceLoader
通过统一的Resource
接口来完成,这个Resource
对各种形式的BeanDefinition
的使用都提供了统一接口。 - 第二个过程是
BeanDefinition
的载入。这个载入过程把用户定义好的Bean表示成IoC容器内部的数据结构。具体来说,这个BeanDefinition
实际上就是POJO对象在IoC容器中的抽象,通过这个BeanDefinition
定义数据结构,使IoC容器能够方便地对POJO对象进行管理。 - 第三个过程是向IoC容器注册这些BeanDefinition的过程。这个过程是通过调用
BeanDefinitionRegistry
接口的实现来完成。这个注册过程把载入过程中解析得到的BeanDefinition
向容器进行注册。在IoC容器内部将BeanDefinition
注入到一个HashMap
中去,IoC容器就是通过这个HashMap
持有这些BeanDefinition
数据。
- IoC容器初始化过程中,一般不包含Bean依赖注入的实现。在Spring IoC的设计中,Bean定义的载入和依赖注入是两个独立的过程。依赖注入一般发生在应用第一次通过
getBean
向容器索取bean的时候。但是有一个例外值得注意,在使用IoC容器时有一个预实例化的配置,通过这个预实例化的配置(具体来说,可以通过为Bean定义信息中的lazyinit
属性),用户可以对容器初始化过程做一个微小的控制,从而改变这个被设置了lazyinit
属性的Bean的依赖注入过程。举例来说,如果我们对某个Bean设置了lazyinit
属性,那么这个Bean的依赖注入在IoC容器初始化时就预先完成了。而不需要等到整个初始化完成以后,第一次使用getBean
时才会触发。
补充:
application完成的事情
- 标识一个应用环境
- 利用beanfactory构建bean对象
- 保存对象关系表
- 各种事件
ConfigurableApplicationContext,context可被修改。构建context种,用户可以动态添加或者修改已有配置信息。最常使用的事可更新的context–AbstractRefreshableApplicationContext
WebApplicationContext,可直接访问ServletContext,通常情况下,使用的少
application完成的事情
- 标识一个应用环境
- 利用beanfactory构建bean对象
- 保存对象关系表
- 各种事件
core中,资源的加载、解析、描述工作委托了ResourcePatternResolver类。
构造器
1 | /** |
refresh()
refersh命名: ApplicationContext 建立起来以后,其实我们是可以通过调用 refresh() 这个方法重建的,refresh() 会将原来的 ApplicationContext 销毁,然后再重新执行一次初始化操作。
1 | public void refresh() throws BeansException, IllegalStateException { |
prepareRefresh()
1 | protected void prepareRefresh() { |
obtainFreshBeanFactory()
1 | protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { |
getBeanFactory()
1 | /** |
prepareBeanFactory()
1 | /** |
finishBeanFactoryInitialization()
1 | /** |
getBean()
1 | public Object getBean(String name) throws BeansException { |
createBean()
1 |
|
initializeBean
1 |
|