接上一篇文章,上一篇重点讲了Spring ioc容器的核心类和整体的体系架构。ioc容器内其实有两大设计主线,一个是BeanFactory一个是ApplicationContext。本章,重点对这两大设计主线进行一探究竟,主要从以下维度出发:
-
BeanFactory与ApplicationContext的应用场景,以及实现原理(只涉及容器的初始化过程,暂不考虑Bean)。
BeanFactory
应用场景
beanFactory提供了最基本的IOC容器的能力。是Spring ioc工厂的顶层规范,定义了很多核心方法。例如:
- getBean, 从工厂中获取一个Bean。
- containsBean,容器内是否包含指定名字的Bean。
- isSingleton,查询指定名字的Bean是否是单例类型。
- ......
类图结构,这里以具体的实现类xmlbeanFactory为例:
相关核心类,简单剖析:
XmlBeanFactory:继承自defaultListableBeanFactory,构造方法支持传入外部的Resource资源,同时持有org.springframework.beans.factory.xml.XmlBeanDefinitionReader这个类,可以直接调用此类,将xml文件转换为Spring内部的数据结构BeanDefinition,最终注册到BeandefinitionRegistry内。
DefaultListableBeanFactory: beanFactory的始祖,spring ioc内部非常核心的一个类,里面实现了大部分beanFactory接口的方法,此类既可以作为一个单独的beanFactory,也可以作为自定义beanFactory的父类。
AbstractAutowireCapableBeanFactory:实现了org.springframework.beans.factory.config.AutowireCapableBeanFactory这个接口,重点是实现了AbstractBeanFactory这个类的createBean方法。提供对Bean创建的支持,属性填充,自动装配和初始化等能力,同时能够处理运行时Bean的音容,解析托管集合,调用初始化方法等。
FactoryBeanRegistrySupport:支持需要处理的,由FactoryBean生成的单例注册的基类。继承DefaultSingletonBeanRegistry类。后面会说一下FactoryBean与BeanFactory的区别。
BeanDefinitionRegistry:beanDefinition注册管理接口,负责对BeanDefinition进行注册,删除,获取等逻辑。
初始化核心流程
public class XmlBeanFactoryTest {
public static void main(String[] args) {
XmlBeanFactory xmlBeanFactory = new XmlBeanFactory(new ClassPathResource("spring-ioc-test1.xml"));
Object bean = xmlBeanFactory.getBean("asdThreadPool");
System.out.println("====Bean====" + bean);
}
}
整体流程:
1)XmlBeanFactory 执行构造方法,因为持有XmlBeanDefinitionReader类,会负责对xml文件进行读取。loadBeanDefinitions会负责把Resource对应的实现类ClassPathResource,读进内存,转换为Document对象。
2)DefaultBeanDefinitionDocumentReader#registerBeanDefinitions,负责把Document对象,转化为Element对象,并对每个Node进行解析。
3)DefaultBeanDefinitionDocumentReader#processBeanDefinition,负责把Element对象转换为BeanDefinitionHolder。
4) BeanDefinitionReaderUtils#registerBeanDefinition,负责把BeanDefinitionHolder注册到Registry内。
5)真正的注册方法:DefaultListableBeanFactory#registerBeanDefinition,把BeanDefinition注册进入beanDefinitionMap内。
能力梳理
BeanFactory作为最上层的接口,提供了一些最基本的能力,如下:
- 根据bean的名称获取实例bean对象。
- 根据bean的名称和class类型获取实例bean对象。
- 是否包含bean.
- 是否是单例bean。
- 是否是原型bean。
- 是否匹配,根据name和class类型去匹配。
ApplicationContext
应用场景
ApplicationContext为Spring ioc提供一些高阶功能,是Spring中的中心接口,提供了一系列可配置的能力,在beanFactory基础之上多了如下功能:
- 以通用方式加载资源文件的能力。继承了ResourceLoader接口。
- 发布注册事件的能力。继承了ApplicationEventPublisher接口。
- 解析资源文件的能力,可以通过资源文件支持国际化。继承了MessageSource接口。
- 有独立的上下文机制,这种上下文可以从父类的上下文继承,但是彼此之间是互相隔离的。(这个特性在我司的dubbo富客户端开发中使用较多,例如:Redis缓存是一个单独的上下文,Memcache缓存是一个单独的上下文,最后可以统一加到父的上下文中,子上下文之间彼此是互相独立的,不影响。)
类图结构
相关核心类,简单剖析
EnvironmentCapable:ApplicationContext接口继承此接口,此接口代表,环境能力接口,此接口代表要指定具体关联的环境。
MessageSource:消息接口,提供对国际化的支持。
ApplicationEventPublisher:发布事件接口,可以发布一个ApplicationEvent类型的事件,也可以发布一个Object类型的事件。
ListableBeanFactory:拓展了BeanFactory接口,同时继承于BeanFactory,可以列举出所有的Bean。例如,通过名称获取bean的列表,通过类型获取bean的列表,通过注解获取bean的列表,获取bean的总个数。
HierarchicalBeanFactory:分层的beanFactory,继承自BeanFactory,内只有两个方法,1)用来获取父的BeanFactory。2)用来判断工厂内是否包含某个Bean。
Lifecycle:生命周期接口,包含开始,停止,是否正在运行三个生命周期阶段的接口。
ResourceLoader:资源load接口,提供了获取Resource的方法,传入一个指定位置,可获取资源。
初始化核心流程
实例代码:
public class ClassPathXmlApplicationContextTest {
public static void main(String[] args) {
ClassPathXmlApplicationContext pathXmlApplicationContext = new ClassPathXmlApplicationContext("spring-ioc-test1.xml");
System.out.println("=======ClassPathXmlApplicationContext=========" + pathXmlApplicationContext);
AsdThreadPool asdThreadPool = pathXmlApplicationContext.getBean("asdThreadPool", AsdThreadPool.class);
System.out.println("============asdThreadPool=========" + asdThreadPool);
}
}
AbstractApplicationContext类的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) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
1.prepareRefresh(); 将active的状态改为True,验证配置文件是否合法。
2.obtainFreshBeanFactory(): 这一块对应的操作比较多,首先会生成DefaultListableBeanFactory对象,其次会对beanFactory进行一些个性化的设置,最后一步是最复杂的,是将xml中定义的bean转换为spring ioc内部的BeanDefinition,最后将BeanDefinition注册到Registry,这段的逻辑和代码,是复用上文BeanFactory注册的逻辑代码。
3.prepareBeanFactory(beanFactory);配置beanFactory,例如设置BeanPostProcesser,BeanClassLoader等。
4.postProcessBeanFactory(beanFactory);留给开发者的一个拓展接口,在此时可以修改BeanFactory内的配置,或者修改BeanDefinition,因为此时工厂内只有BeanDefinition,未有真正的Bean实例。
5.invokeBeanFactoryPostProcessors(beanFactory);实例化并且调用所有注册到上下文中的BeanFactoryPostProcessor。BeanFactoryPostProcessor是Spring的一个拓展点,很多应用都会利用这个拓展点去做一些前置的事情。例如:disconf-client的DisconfMgrBean实现了BeanFactoryPostProcessor的子类BeanDefinitionRegistryPostProcessor,在spring ioc 容器调用invokeBeanFactoryPostProcessors此方法时,postProcessBeanDefinitionRegistry会被触发,此时可以拿到BeanDefinitionRegistry可以对bean做一些个性化的操作。
6.registerBeanPostProcessors(beanFactory);注册beanPostProcessor到工厂内。BeanPostProcessor也是Spring内常用的一个拓展点,可以拿到指定的Bean,在bean初始化之前Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;和bean初始化之后Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;加入自己的逻辑。
7.initMessageSource,初始化所有实现了MessageSource的接口,主要提供对国际化的支持。
8.initApplicationEventMulticaster(); 初始化所有实现ApplicationEventMulticaster接口的类,主要是对多个对象的事件ApplicationEvent进行广播。
9.onRefresh,拓展点,在子bean工厂内初始化其他的指定的一些bean。
10.registerListeners,注册applicationEvent的监听器。
11.finishBeanFactoryInitialization(beanFactory);初始化所有剩余的单例类(非惰性初始化的类)。 default-lazy-init="false"即非惰性初始化,这样的话,bean在spring ioc容器启动过程中,单例的bean就被初始化了。如果default-lazy-init="true",则会在getBean这个操作,才会将bean进行初始化。大多数情况,为了减少请求的rt,最好是在系统启动时将bean都已经实例化好。
12.finishRefresh(); 1)初始化上下文中所有实现了LifeCycleProcessor接口的类。2)执行所有实现了LifecycleProcessor接口的onRefresh方法。3)发布ContextRefreshedEvent事件。4)把spring内所有存活的bean,通过mbean的方式暴露出来,即提供了一个对所有存活bean的监控。这个有点意思。
总结
- beanFactory的初始化相对而言比较简单,主要是对Resource资源解析为BeanDefinition,同时注册到Registry内。BeanFactory作为Spring ioc容器的顶层接口,提供了一些最基本通用的能力。
- ApplicationContext的初始化非常复杂,refresh方法内每个初始化的方法,逻辑深入一看都比较复杂,这里只是提炼了一些最基本的。ApplicationContext的启动过程中,提供了很多拓展点。spring的拓展点实在是太好用了,设计真的是太精妙了。spring的拓展点具体是如何与启动过程结合起来的,这块还需要具体去分析。
下章预览
- FactoryBean与BeanFactory的区别?
- Spring内一些常见的拓展点,以及如何使用,对应的案例?
- Spring内拓展点是如何与ioc的启动过程结合到一起的?