spring源码分析之IoC容器分析
前言
有时候去面试总会碰到问IoC原理的,但是很少看到问IoC分为哪几类,IoC与DI有什么区别,其实比较反感这种概念性的问题。04年的时候MartinFowler已经把这些东西解释了一遍,感兴趣的就到这里,在这篇博客的参考文献发现80年代国外的叫兽就在论文里面提到了这些东西了,只是MartinFowler归纳总结出了个概念。既然写出来了,还是说说自己的理解。IoC翻译为控制反转,就是对bean的控制反转了,电影中有剧情反转、体育比赛有比赛反转等等,说得广泛点这些都可以看做是IoC,而java的实现就是跟bean相关的事情都不用自己去做了,都交给spring管理(有点像软件中的外包吧)。从下图也可以看出这几者的关系了:
此图出自spring的作者Rod Johnson的《Expert One-on-One J2EE Development without EJB》一书。在spring内部中还是有使用了Dependency Lookup(依赖查找)方式的,如BeanFactoryAware、ApplicationContextAware,这些只是针对比较特殊处理,spring大部分还是使用DI方式。由于此书2004年就出版了,当时的JDK版本还没有注解,所以后来spring的版本DI的方式还有通过注解注入(包含field inject)。
spring的两种容器
分析源码之前,把API转换成类图,这些容器之间的关系其实就比较清晰了。spring的IoC容器主要分为两类,一个是BeanFactory,一个是ApplicationContext,如下图所示(基于4.2.3分支):
BeanFactory
BeanFactory作为最顶层的工厂,只提供了获取bean最基本的操作,其他操作又抽象出了4个工厂:
HierarchicalBeanFactory:设置bean的一种层级关系,可以获取父类的BeanFactory(如果在当前容器中没有找到还可以到父类容器中去找bean)。
ListableBeanFactory:可以列举所有的bean的名字,在内部解析的时候,经常用到,但只会涉及到当前容器的bean,不会像HierarchicalBeanFactory去找父类BeanFactory的bean。
AutowireCapableBeanFactory:创建bean的工厂,bean的依赖实现也是由此工厂处理。
ConfigurableBeanFactory:一般与BeanFactory、ListableBeanFactory一起使用,设置一些初始化配置操作,包括bean是singleton还是prototype, setParentBeanFactory,setConversionService,addPropertyEditorRegistrar,registerCustomEditor,addBeanPostProcessor等等。
AbstractBeanFactory
BeanFactory的抽象实现类,实现了bean的判断以及获取bean的入口。
AbstractAutowireCapableBeanFactory
处理bean的实例化操作,也包括处理前、处理后一些操作,在后面分析代理bean初始化再详细介绍。
DefaultListableBeanFactory
DefaultListableBeanFactory作为BeanFactory的具体实现类,是整个IoC容器最核心的一个类,只要涉及到容器,就离不开DefaultListableBeanFactory,该类实现了注册bean、缓存bean names(解析bean的时候用到),具体的的依赖关系参考下图:
ApplicationContext
相比BeanFactory,ApplicationContext继承了更多的接口,功能更强大,
- bean具有层级关系(父子关系)
- 可以触发监听事件
- 实现了ResoureLoader可以加载配置文件
- 默认注册PropertyEditors,由BeanWrapperImpl实现属性类型转换
- 内部实现了对BeanPostProcessor内置对象的处理
所以实际运用中,一般都使用的ApplicationContext类型的IoC容器
AbstractApplicationContext
与AbstractBeanFactory一样,只要继承了AbstractApplicationContext,这个容器获取bean的入口就在这个抽象类中,可以参考refresh方法:
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
这个方法包含了初始化bean、实例化bean之前的一些操作、初始化国际化资源文件、注册各种监听器等等, AbstractApplicationContext内部存储bean其实都是由DefaultListableBeanFactory完成,后面bean分析的时候详细说明。
如果说得再细一点还可以把WebApplicationContext归为一类容器,但作为ApplicationContext的子类,里面的实现几乎没什么区别,只是WebApplicationContext里面多了对servlet相关类的处理,所以分为两大类就可以了。
总结
spring的IoC容器是整个框架最核心的部分,只要把这部分弄明白了,其他模块也就迎刃而解了,参考下图(来自spring官方文档):
参考文献
《Expert One-on-One J2EE Design and Development》
《Expert One-on-One J2EE Development without EJB》
《Professional Java Development with the spring framework》