spring学习总结002 --- IOC容器启动源码(简易版)
Posted sniffs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring学习总结002 --- IOC容器启动源码(简易版)相关的知识,希望对你有一定的参考价值。
这张图是最最简单的处理流程图,其中还省略了初始化国际化、事件广播器等流程;下面参照ClassPathXmlApplicationContext源码,记录下IOC容器启动的大致流程:
1、ClassPathXmlApplicationContext构造器
public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } }
先为IOC容器设置了配置文件路径,然后执行IOC启动最核心的方法:refresh()
2、refresh方法
refresh方法实现位于ClassPathXmlApplicationContext的父类AbstractApplicationContext,主要有如下几个功能:
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // 容器刷新的准备工作 prepareRefresh(); // 创建BeanFactory, 读取配置文件中bean的定义 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // 对BeanFactory进行初始化 prepareBeanFactory(beanFactory); try { // 钩子方法, 子类进行扩展 postProcessBeanFactory(beanFactory); // 执行BeanFactoryPostProcessor invokeBeanFactoryPostProcessors(beanFactory); // 注册BeanPostProcessor registerBeanPostProcessors(beanFactory); // 初始化国际化信息 initMessageSource(); // 初始化事件广播器 initApplicationEventMulticaster(); // 钩子方法, 子类进行扩展 onRefresh(); // 注册事件监听器 registerListeners(); // 初始化单例bean(未配置lazz-init) finishBeanFactoryInitialization(beanFactory); // 容器启动最后一步: 事件推送 finishRefresh(); } } }
3、prepareRefresh方法
protected void prepareRefresh() { // 设置启动时间和启动标记 this.startupDate = System.currentTimeMillis(); this.closed.set(false); this.active.set(true); // 钩子方法, 用户自行实现初始化属性 initPropertySources(); // 验证所有必要属性, 必要属性来源: // 1、ConfigurablePropertyResolver#setRequiredProperties // 2、用户扩展的initPropertySources getEnvironment().validateRequiredProperties(); // 允许应用启动之前的事件,当multicaster一旦可用的时候,可用立刻响应发布的事件。 this.earlyApplicationEvents = new LinkedHashSet<>(); }
里面有一个钩子方法,由子类实现其功能;我在实际项目中使用initPropertySources,强制要求某些环境变量必须存在
示例:
public class MyAbstractApplicationContext extends ClassPathXmlApplicationContext { public MyAbstractApplicationContext(String configLocation) throws BeansException { super(configLocation); } @Override protected void initPropertySources() { super.initPropertySources(); // 设置TEST_ENV环境变量为必要的, 如果没有, IOC容器启动失败 getEnvironment().setRequiredProperties("TEST_ENV"); } }
运行结果:
4、obtainFreshBeanFactory方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() { // 创建BeanFactory, 然后解析并保存Bean定义 refreshBeanFactory(); // 返回BeanFactory return getBeanFactory(); }
protected final void refreshBeanFactory() throws BeansException { // 存在BeanFactory, 先销毁 if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { // 创建BeanFactory DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); // 定制BeanFactory, 根据Application的配置, 决定BeanFactory是否允许重复依赖和Bean名称重复 customizeBeanFactory(beanFactory); // 解析并保存Bean定义信息 // 保存在DefaultListableBeanFactory.beanDefinitionMap loadBeanDefinitions(beanFactory); // 设置为全局BeanFactory this.beanFactory = beanFactory; } catch (IOException ex) { throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
customizeBeanFactory方法可以为BeanFactory设置是否允许bean循环依赖以及是否允许bean名称重复
以上是关于spring学习总结002 --- IOC容器启动源码(简易版)的主要内容,如果未能解决你的问题,请参考以下文章
spring学习总结007 --- IOC容器级生命周期接口