Spring源码深度解析-2
容器的扩展功能
以ApplicationContext 切入点:
final ApplicationContext applicationContext = new ClassPathXmlApplicationContext("MyTestBean.xml");
final MyTestBean myTestBean = (MyTestBean)applicationContext.getBean("myTestBean");
assert myTestBean.getS().equals("test");
1、设置配置路径
2、扩展功能
集中查看refresh()方法
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1、准备刷新上下文环境
prepareRefresh();
// 2、初始化BeanFactory 并进行XMLd读取
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 3、对BeanFactory进行各种功能填充例如@Qualifier 和@Autowired注解等
prepareBeanFactory(beanFactory);
try {
// 4、子类覆盖父类方法做额外的处理
postProcessBeanFactory(beanFactory);
// 5、激活各种BeanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 6、注册拦截bean创建的bean处理器
registerBeanPostProcessors(beanFactory);
// 7、为上下文初始化Message源,对不同的消息体进行国际化处理
initMessageSource();
// 8、初始化应用消息广播器,并放入applicationEventMulticaster bean中;
initApplicationEventMulticaster();
// 9、留给子类来初始化其他的bean
onRefresh();
// 10、在所有注册的bean中查找listener bean ,注册到消息广播器中
registerListeners();
// 11、初始化剩下的单实例(非惰性的)
finishBeanFactoryInitialization(beanFactory);
// 完成刷新过程,通知声明周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
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();
}
}
}
3、环境准备
- prepareRefresh();
- initPropertySources 留给子类覆盖,符合Spring开放式结构设计,给用户最大扩展Spring的能力 ;
- validateRequiredProperties 则是对属性进行验证
public class MyClassPathXmlAppCon extends ClassPathXmlApplicationContext {
public MyClassPathXmlAppCon(String... configLocation) throws BeansException {
super(configLocation);
}
@Override
protected void initPropertySources() {
//添加验证要求
getEnvironment().setRequiredProperties("VAR");
}
}
4、加载BeanFactory
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//1、创建DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//2、指定序列化Id
beanFactory.setSerializationId(getId());
//3、定制BeanFactory
customizeBeanFactory(beanFactory);
//4、加载BeanDefinition
loadBeanDefinitions(beanFactory);
//5、使用全局变量记录beanFactory
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
4-1、定制BeanFactory
4-2、加载 BeanDefinition
为指定的beanFactory初始化相应的XmlBeanDefinitionReader,并进行环境变量的设置,使用loadBeanDefinitions(XmlBeanDefinitionReader)进行加载;
5、功能扩展
prepareBeanFactory方法
6、BeanFactory的后处理
6-1、激活注册的BeanFactoryPostProcesser
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
- SpringIoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其他的bean之前读取元素据,并可能修改它;
- 如果想要改变实际的bean实例,最好使用BeanPostProcessor;BeanFactoryPostProcessor的作用域是容器级的,如果你在容器中定义一个BeanFactoryPostProcesser,他只会对此容器中的bean进行后置处理。
- 典型应用:PropertyPlaceholderConfigurer
- 参考链接
- 自定义BeanFactoryPostProcesser
- 激活BeanFactoryPostProcesser
6-2、注册BeanPostProcessor
registerBeanPostProcessors(beanFactory);
6-3、初始化消息资源
initMessageSource();
6-4、初始化ApplicationEventMulticaster
initApplicationEventMulticaster()
- 如果用户自定义了事件广播器,那么使用用户自定义的事件广播器。
- 如果用户没有自定义事件广播器,那么使用默认的ApplicationEventMulticaster。
- (转)了解Spring的事件监听机制
6-5、注册监听器
registerListeners();
7、初始化非延迟加载单例
finishBeanFactoryInitialization();
- ConverionService的设置
- 配置冻结(冻结所有的bean定义,说明注册的bean定义将不被修改或进行任何进一步的处理)
- 非延迟加载bean的操作(ApplicationContext的默认行为是在启动时将所有单例bean提前进行实例化)
8、finishReresh
- initLifecycleProcessor():通过LifecycleProcessor来与所有声明的bean的周期做状态更新;
- onRefresh():启动所有实现Lifecyce接口的bean;
- publishEvent():要通过Spring中的事件发布机制来发出;ContextRefreshedEvent事件,以保证对应的监听器来做进一步的逻辑处理;
参考书籍《Spring源码深度解析》