原创:springMVC源码深度剖析-(初始化springMVC容器)

在上一篇文章原创:springMVC源码深度剖析-(初始化)中讲到了创建本地上下文createWebApplicationContext(rootContext)的具体实现,接下来主要看创建上下文时初始化springMVC容器的部分

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
        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");
        }
        //通过反射创建mvc容器
        ConfigurableWebApplicationContext wac =
                (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
        //设置环境
        wac.setEnvironment(getEnvironment());
        //设置根上下文为父上下文
        wac.setParent(parent);
        //设置springmvc.xml的路径
        wac.setConfigLocation(getContextConfigLocation());
        //初始化springmvc容器以及各种的相关配置,各种注入的Controller,配置文件等  
        configureAndRefreshWebApplicationContext(wac);

        return wac;
    }

1.configureAndRefreshWebApplicationContext(wac)

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
        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 {
                // 设置id.
                wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                        ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
            }
        }

        wac.setServletContext(getServletContext());
        wac.setServletConfig(getServletConfig());
        //设置springmvc配置文件的名称
        wac.setNamespace(getNamespace());
        wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

        ConfigurableEnvironment env = wac.getEnvironment();
        if (env instanceof ConfigurableWebEnvironment) {
            ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
        }

        //默认实现是空的
        postProcessWebApplicationContext(wac);
        applyInitializers(wac);
        //初始化springmvc容器以及各种的相关配置,各种注入的Controller,配置文件等  
        wac.refresh();
    }

其中最重要的方法就是wac.refresh();,接下来我们将详细进行解析


2.wac.refresh()

public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 准备对上下文进行刷新
            prepareRefresh();

            // 初始化beanFactory 
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 为BeanFactory配置容器特性,例如类加载器、事件处理器等
            prepareBeanFactory(beanFactory);

            try {
                // 为容器的某些子类指定特殊的BeanPost事件处理器
                postProcessBeanFactory(beanFactory);

                // 调用beanFactory处理器
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注册beanFactory处理器.
                registerBeanPostProcessors(beanFactory);

                // 初始化消息源
                initMessageSource();

                // 初始化上下文事件广播.
                initApplicationEventMulticaster();

                // 初始化其它特殊bean,由子类来实现
                onRefresh();

                // 注册事件监听器.
                registerListeners();

                // 初始化所有单实例的bean,使用懒加载除外
                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();
            }
        }
    }

这个方法做了很多事情,我们接下来只对重要的功能进行解析


2.1 obtainFreshBeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
        //创建BeanFactory(先销毁所有的bean,然后在创建一个BeanFactory,最后在赋值)
        refreshBeanFactory();
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (logger.isDebugEnabled()) {
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
        }
        return beanFactory;
    }

创建BeanFactory会先销毁所有的bean,然后在创建一个BeanFactory,接下来我们看一下它是怎么执行的

@Override
    protected final void refreshBeanFactory() throws BeansException {
        //如果BeanFactory存在,就会进行销毁和关闭
        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }
        try {
            //创建BeanFactory
            DefaultListableBeanFactory beanFactory = createBeanFactory();
            beanFactory.setSerializationId(getId());
            customizeBeanFactory(beanFactory);
            //加载配置文件
            loadBeanDefinitions(beanFactory);
            synchronized (this.beanFactoryMonitor) {
                this.beanFactory = beanFactory;
            }
        }
        catch (IOException ex) {
            throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
        }
    }

createBeanFactory: 在创建BeanFactory的同时会判断是否有父BeanFactory,如果有设置,如果没有就不设置。

protected BeanFactory getInternalParentBeanFactory() {
        //在创建BeanFactory的同时会判断是否有父BeanFactory,如果有设置,如果没有就不设置。
        return (getParent() instanceof ConfigurableApplicationContext) ?
                ((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent();
    }

loadBeanDefinitions(beanFactory):负责加载配置文件等信息,我们来看一下源代码

@Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // Create a new XmlBeanDefinitionReader for the given BeanFactory.
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);


        // 设置坏境
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        //设置资源加载器
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        initBeanDefinitionReader(beanDefinitionReader);
        //加载配置文件
        loadBeanDefinitions(beanDefinitionReader);
    }

loadBeanDefinitions(beanDefinitionReader):由AbstractRefreshableWebApplicationContext父类AbstractRefreshableConfigApplicationContext实现getConfigLocations方法,获取了web.xml配置的param-value的值,然后保存在数组里面

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
        //获取web.xml中<param-value>的值
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            for (String configLocation : configLocations) {
                //读取配置文件
                reader.loadBeanDefinitions(configLocation);
            }
        }
    }

loadBeanDefinitions(configLocation):现在获取了param-value的值,接下去就开始读取配置文件,源代码如下

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
        ResourceLoader resourceLoader = getResourceLoader();
        if (resourceLoader == null) {
            throw new BeanDefinitionStoreException(
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
        }

        if (resourceLoader instanceof ResourcePatternResolver) {
            try {
                //加载web.xml配置的param-value对应的资源
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
                //对加载进来的资源进行解析并注册,也就是把用户定义的数据结构转化为 Ioc 容器中的特定数据结构
                int loadCount = loadBeanDefinitions(resources);
                if (actualResources != null) {
                    for (Resource resource : resources) {
                        actualResources.add(resource);
                    }
                }
                if (logger.isDebugEnabled()) {
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                }
                return loadCount;
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);
            }
        }
        else {
            // Can only load single resources by absolute URL.
            Resource resource = resourceLoader.getResource(location);
            int loadCount = loadBeanDefinitions(resource);
            if (actualResources != null) {
                actualResources.add(resource);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }
            return loadCount;
        }
    }

总结:

(1)SpringMVC先创建BeanFactory时先销毁所有Bean,关闭BeanFactory,然后重新创建一个BeanFactory,并将其赋给BeanFactory实例变量。

(2)创建好了BeanFactory,并设置好环境,并然后通过ResourcePatternResolver加载web.xml配置的param-value对应的资源,loadBeanDefinitions进行对加载进来的资源进行解析,在解析之前先进行转码,是通过EncodedResource对资源文件进行转码

(3)对读取进来的配置文件进行验证,是否是XML格式的,然后配置文件中的Bean的id、name、class等属性的解析并设置到BeanDefinition然后放到放到BeanDefinitionHolder中,并放入到IOC容器中建立对应的数据结构。是以Document形式的存储的。

喜欢的话请关注并点击下一篇,持续更新中

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值