实例化一个spring容器(ClassPathXmlApplicationContext)

ClassPathXmlApplicationContext的构造方法如下:

    /**
     * Create a new ClassPathXmlApplicationContext, loading the definitions
     * from the given XML file and automatically refreshing the context.
     * @param configLocation resource location
     * @throws BeansException if context creation failed
     */
    public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
        this(new String[] {configLocation}, true, null);
    }

    /**
     * Create a new ClassPathXmlApplicationContext with the given parent,
     * loading the definitions from the given XML files.
     * @param configLocations array of resource locations
     * @param refresh whether to automatically refresh the context,
     * loading all bean definitions and creating all singletons.
     * Alternatively, call refresh manually after further configuring the context.
     * @param parent the parent context
     * @throws BeansException if context creation failed
     * @see #refresh()
     */
    public ClassPathXmlApplicationContext(
            String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
            throws BeansException {

        super(parent);
        // 保存配置文件定位信息到configLocations中,即[consumer.xml]
        setConfigLocations(configLocations);
        if (refresh) {
            // 初始化容器
            refresh();
        }
    }

实现一个ClassPathXmlApplicationContext上下文环境主要做了三件事

  1. 调用父类的构造方法(AbstractApplicationContext)
  2. 设置配置文件地址
  3. 初始化容器

首先我们来看其父类的构造方法:

    /**
     * Create a new AbstractApplicationContext with no parent.
     */
    public AbstractApplicationContext() {
        this.resourcePatternResolver = getResourcePatternResolver();
    }

    /**
     * Create a new AbstractApplicationContext with the given parent context.
     * @param parent the parent context
     */
    public AbstractApplicationContext(@Nullable ApplicationContext parent) {
        this();
        setParent(parent);
    }
    protected ResourcePatternResolver getResourcePatternResolver() {
        return new PathMatchingResourcePatternResolver(this);
    }
    
    public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
        Assert.notNull(resourceLoader, "ResourceLoader must not be null");
        this.resourceLoader = resourceLoader;
    }

可以发现,在其父类的构造方法中主要设置了资源的加载器以及解析器。

接下来对配置文件进行设置,这个方法是在AbstractRefreshableConfigApplicationContext类中实现的:

    @Nullable
    // 配置文件的地址信息会保存到这里
    private String[] configLocations;
    /**
     * Set the config locations for this application context.
     * <p>If not set, the implementation may use a default as appropriate.
     */
    public void setConfigLocations(@Nullable String... locations) {
        if (locations != null) {
            Assert.noNullElements(locations, "Config locations must not be null");
            this.configLocations = new String[locations.length];
            for (int i = 0; i < locations.length; i++) {0
                // 将配置文件路径信息保存到configLocation中s
                this.configLocations[i] = resolvePath(locations[i]).trim();
            }
        }
        else {
            this.configLocations = null;
        }
    }

最后就是初始化容器的方法了,此方法在AbstractApplicationContext类中实现:

    @Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 准备工作,记录下容器的启动时间、标记“已启动”状态、处理配置文件中的占位符
            // Prepare this context for refreshing.
            prepareRefresh();
            // 这里会将配置文件中的Bean以BeanDefinition的形式注册到容器中(obtain:得到)
            // Tell the subclass to refresh the internal bean factory.
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
            // 配置bean工厂(设置类加载器,时间处理器等)
            // Prepare the bean factory for use in this context.
            prepareBeanFactory(beanFactory);

            try {
                // Allows post-processing of the bean factory in context subclasses.
                // 允许子类对bean工厂做一些后处理
                postProcessBeanFactory(beanFactory);

                // Invoke factory processors registered as beans in the context.
                // 调用注册在上线文中beanfactory的后处理方法
                invokeBeanFactoryPostProcessors(beanFactory);

                // Register bean processors that intercept bean creation.
                // 注册bean的后置处理器
                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实例化之前初始化一些特殊的bean
                onRefresh();

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

                // Instantiate all remaining (non-lazy-init) singletons.
                // 实体化单例非懒惰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.
                // 销毁bean
                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定义,配置bean工程,对后置处理器进行调用或者注册,实例化bean等,接下来我将逐个对这些方法进行源码的分析。