源码解析 XmlWebApplicationContext

XmlWebApplicationContext是Spring中重要的Web应用上下文,主要用在DispatcherServlet和ContextLoaderListener。初始化分为配置阶段和刷新阶段,其中刷新阶段涉及BeanFactory的生命周期。在getBean过程,会经过AbstractApplicationContext和DefaultListableBeanFactory的相关方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

XmlWebApplicationContext 是使用最频繁的 WebApplicationContext,值得深入了解和学习

它既是 DispatcherServlet 的 (WebApplicationContext)默认策略,又是 ContextLoaderListener 创建 root WebApplicationContext(根容器,同时也是 DispatcherServlet 的 WebApplicationContext 的父容器)的默认策略

继承体系

这里写图片描述


1.初始化流程

此处参考 DispatcherServlet 其中一段初始化的源码,这是专门用来初始化 XmlWebApplicationContext 的,可作为模范代码去借鉴:查看 DispatcherServlet 的父类 FrameworkServlet 的 createWebApplicationContext(…) 方法源码

//初始化 WebApplicationContext
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
    //默认是 XmlWebApplicationContext
    Class<?> contextClass = getContextClass();
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Servlet with name '" + getServletName() +
                "' will try to create custom WebApplicationContext context of class '" +
                contextClass.getName() + "'" + ", using parent context [" + parent + "]");
    }
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
        throw new ApplicationContextException(
                "Fatal initialization error in servlet with name '" + getServletName() +
                "': custom WebApplicationContext class [" + contextClass.getName() +
                "] is not of type ConfigurableWebApplicationContext");
    }
    //初始化:调用无参构造函数
    ConfigurableWebApplicationContext wac =
            (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

    //设置环境参数
    wac.setEnvironment(getEnvironment());
    //设置父ApplicationContext(一般都为root ApplicationContext)
    wac.setParent(parent);
    //设置“配置文件路径”(在后续的“刷新”阶段才会加载XML配置)
    wac.setConfigLocation(getContextConfigLocation());

    //配置并“刷新”容器
    configureAndRefreshWebApplicationContext(wac);

    return wac;
}

//配置并“刷新”容器
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
    //设置一个更有用的并且唯一的 ApplicationContext id
    if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
        // The application context id is still set to its original default value
        // -> assign a more useful id based on available information
        if (this.contextId != null) {
            wac.setId(this.contextId);
        }
        else {
            // Generate default id...
            wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                    ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
        }
    }

    wac.setServletContext(getServletContext());
    wac.setServletConfig(getServletConfig());
    wac.setNamespace(getNamespace());
    //此处注册一个监听器:当ApplicationContext进行“刷新”时,onApplicationEvent(..)方法将被回调,进而触发模板方法:onRefresh(..)
    //身为子类的DispatcherServlet就是利用这一点,通过重写该模板方法,实现了各类组件初始化(包括HandlerMapping、HandlerAdapter、ViewResolver)
    //各类组件的初始化策略中既存在默认策略,也允许自定义配置,了解其配置有助于了解SpringMVC体系架构,请自行查阅相关源码
    wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

    // The wac environment's #initPropertySources will be called in any case when the context
    // is refreshed; do it eagerly here to ensure servlet property sources are in place for
    // use in any post-processing or initialization that occurs below prior to #refresh
    ConfigurableEnvironment env = wac.getEnvironment();
    if (env instanceof ConfigurableWebEnvironment) {
        ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
    }

    //模板回调方法,可由子类实现,用来修改WebApplicationContext配置信息
    postProcessWebApplicationContext(wac);
    //提供给ApplicationContextInitializer接口介入的机会,可用来修改WebApplicationContext配置信息
    applyInitializers(wac);
    //刷新ApplicationContext配置信息(包括加载XML资源、属性文件等)
    wac.refresh();
}

可以看到,初始化 XmlWebApplicationContext 主要分为两阶段:(1)【配置阶段】设置各种重要属性,包括设置配置文件路径;(2)【刷新阶段】调用 XmlWebApplicationContext 的 refresh(),该方法涉及容器(或者说BeanFactory)的整个生命周期

【刷新阶段】:查看 refresh() 方法源码,该方法由 XmlWebApplicationContext 的父类 AbstractApplicationContext 实现

@Override
public void refresh() throws BeansException, IllegalStateException {
    //加锁,同步ApplicationContext的“刷新”或“销毁”阶段
    synchronized (this.startupShutdownMonitor) {
        //“刷新”阶段的事前准备(比如启动计时、标记状态位等)
        prepareRefresh();

        //①刷新内部的BeanFactory(默认为DefaultListableBeanFactory)
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

        //BeanFactory的准备阶段,配置一些重要属性(例如ClassLoader、post-processors)
        prepareBeanFactory(beanFactory);

        try {
            //②模板方法,可由子类(AbstractRefreshableWebApplicationContext)重写
            //(当前进度:BeanFactory里全部的Bean配置已加载,但未进行实例化)
            postProcessBeanFactory(beanFactory);

            //实例化BeanFactory里所有的BeanFactoryPostProcessor,并依据排序进行调用
            //(开发者可据此配置一个自定义的BeanFactoryPostProcessor,以介入容器的生命周期)
            invokeBeanFactoryPostProcessors(beanFactory);

            //收集并注册BeanFactory里所有的BeanPostProcessor
            //(开发者可据此配置一个自定义的BeanPostProcessor,以介入Bean的生命周期)
            registerBeanPostProcessors(beanFactory);

            //初始化 MessageSource(事件源)
            initMessageSource();

            //初始化 ApplicationEventMulticaster(应用事件多路广播)
            initApplicationEventMulticaster();

            //模板方法,可由子类重写(初始化ThemeSource)
            //(当前进度:特殊的Bean已初始化完成,比如BeanPostProcessor,但singleton bean未进行实例化)
            onRefresh();

            //收集并注册所有的ApplicationListener,如果存在“提前事件”,将其广播出去
            registerListeners();

            //③实例化并缓存所有的singleton bean,除了延迟加载的
            //(当前进度:内部BeanFactory已初始化完成)
            finishBeanFactoryInitialization(beanFactory);

            //最后一步,发布相应的事件
            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个

①刷新内部的BeanFactory(默认为DefaultListableBeanFactory):查看 obtainFreshBeanFactory() 方法源码

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    //模板抽象方法,由子类实现(AbstractRefreshableApplicationContext)
    refreshBeanFactory();
    //获取“刷新”后的BeanFactory,
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (logger.isDebugEnabled()) {
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
    }
    return beanFactory;
}

由上,查看 AbstractRefreshableApplicationContext 的 refreshBeanFactory() 方法源码

@Override
protected final void refreshBeanFactory() throws BeansException {
    //销毁已存在的BeanFactory
    if (hasBeanFactory()) {
        //回收 singleton bean 缓存,方便GC
        destroyBeans();
        //设为null,方便GC
        closeBeanFactory();
    }
    //创建并初始化一个新的 DefaultListableBeanFactory
    try {
        DefaultListableBeanFactory beanFactory = createBeanFactory();
        beanFactory.setSerializationId(getId());
        //设置状态位,以允许重写BeanFactory配置
        customizeBeanFactory(beanFactory);
        //模板抽象方法(加载XML资源配置),由子类重写
        loadBeanDefinitions(beanFactory);
        synchronized (this.beanFactoryMonitor) {
            this.beanFactory = beanFactory;
        }
    }
    catch (IOException ex) {
        throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    }
}

②模板方法,可由子类重写(AbstractRefreshableWebApplicationContext):查看被重写的 postProcessBeanFactory(..) 方法源码

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //注册ServletContextAwareProcessor,管理servletContext、servletConfig的依赖注入
    beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
    //忽视ServletContextAware接口的默认依赖注入
    beanFactory.ignoreDependencyInterface(ServletContextAware.class);
    //忽视ServletConfigAware接口的默认依赖注入
    beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

    //注册各种作用域的实现机制(比如request、session)
    WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
    //收集并注册应用环境参数("contextParameters", "contextAttributes")
    WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}

③实例化并缓存所有的singleton bean,除了延迟加载的:查看 AbstractApplicationContext 的 finishBeanFactoryInitialization(..) 方法源码

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
    // Initialize conversion service for this context.
    if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
            beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
        beanFactory.setConversionService(
                beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
    }

    // Register a default embedded value resolver if no bean post-processor
    // (such as a PropertyPlaceholderConfigurer bean) registered any before:
    // at this point, primarily for resolution in annotation attribute values.
    if (!beanFactory.hasEmbeddedValueResolver()) {
        beanFactory.addEmbeddedValueResolver(new StringValueResolver() {
            @Override
            public String resolveStringValue(String strVal) {
                return getEnvironment().resolvePlaceholders(strVal);
            }
        });
    }

    // Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
    String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
    for (String weaverAwareName : weaverAwareNames) {
        getBean(weaverAwareName);
    }

    //停止使用临时的类加载器
    beanFactory.setTempClassLoader(null);

    //冻结Bean配置信息,不再被修改,并支持进一步缓存
    beanFactory.freezeConfiguration();

    //确保实例化所有的singleton bean,除了延迟加载(懒加载)
    //(singleton作用域的bean可支持缓存、SmartInitializingSingleton接口等)
    beanFactory.preInstantiateSingletons();
}

2.查看getBean(String name)源码

查看 XmlWebApplicationContext 的 getBean(String name) 方法源码,该方法由父类 AbstractApplicationContext 实现

@Override
public Object getBean(String name) throws BeansException {
    //验证内部的BeanFactory处于“激活”状态
    assertBeanFactoryActive();
    //默认采用的是 DefaultListableBeanFactory
    return getBeanFactory().getBean(name);
}

后续流程可参考 DefaultListableBeanFactory 的 getBean(String name) 方法源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值