ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

首先可以看到ClassPathXmlApplicationContext继承于BeanFactory和ResourceLoader两个父类接口。

我们再来看ClassPathXmlApplicationContext的构造方法做了什么

//调用了自己的另一个构造方法
public ClassPathXmlApplicationContext(String... configLocations) throws BeansException {
   this(configLocations, true, null);
}
/**
调用了父类的构造方法,同时设置了配置文件的地址,并判断是否刷新
**/
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {

   super(parent);
   setConfigLocations(configLocations);
   if (refresh) {
      refresh();
   }
}

跟进源码里面,super(parent),一直调用到了AbstractApplicationContext类

/**
 * Create a new AbstractApplicationContext with the given parent context.
 * 第一次传递的parent为null
 * @param parent the parent context
 */
public AbstractApplicationContext(ApplicationContext parent) {
   this();
   setParent(parent);
}

其中this()方法

/**
 * Create a new AbstractApplicationContext with no parent.
 * 获取了一个资源解析器
 */
public AbstractApplicationContext() {
   this.resourcePatternResolver = getResourcePatternResolver();
}

所以在初始化的第一步就是设置了一个资源的解析器,让我们再回到第一步的初始化方法

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
      throws BeansException {

/**
 * Create a new AbstractApplicationContext with no parent.
 * 获取了一个资源解析器
 */
   super(parent);
/**
 * Create a new AbstractApplicationContext with no parent.
 * 设置配置文件的地址
 */
   setConfigLocations(configLocations);
/**
 * Create a new AbstractApplicationContext with no parent.
 * 重点在这个refresh方法
 */
   if (refresh) {
      refresh();
   }
}

refresh()方法是实现了ConfigurableApplicationContext接口的refresh方法,

进入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.
      // 告诉子类刷新内部bean工厂,如果beanfactory已存在会先销毁所有的bean,然后关闭beanfactory。然后创建beanfactory,加载beanDefinitions(bean定义)
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      // Prepare the bean factory for use in this context.
      // 准备beanfactory供context使用
      prepareBeanFactory(beanFactory);

      try {
         // Allows post-processing of the bean factory in context subclasses.
         // 允许子类在context中的子类执行后置操作
         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.
         /// 初始化其他特殊的bean
         onRefresh();

         // Check for listener beans and register them.
         // 注册监听者
         registerListeners();

         // Instantiate all remaining (non-lazy-init) singletons.
         // 初始化所有非lazy的单例bean
         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();
      }
   }
}

refresh()方法没有具体的展开,下次继续学习bean的初始化部分。整个启动的流程可以简单的总结一下为以下流程。

Spring IOC启动流程学习(一)-LMLPHP

02-08 22:28