这张图是最最简单的处理流程图,其中还省略了初始化国际化、事件广播器等流程;下面参照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名称重复
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { // 是否允许覆盖重复bean定义 if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // 是否允许循环依赖 if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }
spring有如下的行为:如果一个bean配置文件中存在两个及以上id或者name相同的bean,name直接抛出异常;如果不同配置文件中存在两个及以上id或者name相同的bean,默认会进行覆盖处理(可配置);
bean重复定义检查的流程在BeanFactory解析BeanDefination中,至于循环依赖,在另外的文章中说明。
不允许bean重复简单示例
public static void main(String[] args) { MyAbstractApplicationContext applicationContext = new MyAbstractApplicationContext("classpath:bean5.xml", "classpath:bean6.xml"); applicationContext.setAllowBeanDefinitionOverriding(false); applicationContext.refresh(); Name name = (Name) applicationContext.getBean("name"); log.info(name.toString()); }
运行结果:
5、prepareBeanFactory
BeanFactory的准备阶段,这块没细看,只是知道忽略了生命周期相关接口的bean定义
6、postProcessBeanFactory
钩子方法,由子类实现;该方法用于在BeanFactory创建后对BeanFactory做一些定制化,如忽略某些接口的自动装配
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { }