springMVC框架初始化流程的初步理解

来源:互联网 发布:达达妈淘宝店卖假货吗 编辑:程序博客网 时间:2024/06/05 08:05

场景

前段时间工作上的任务比较闲,就拐回去看了看spring的工作机制相关的东西,进而想到了要看看springMVC框架的实现思路,用了有半年了还不知道它内部的实现原理,所以这次想一探究竟。

servlet机制

可以参考这篇文章,说得很详细

上下文环境

ServletContext接口定义了运行Servlet的应用程序环境的一些行为和观点,可以使用ServletContext实现对象来取得锁清秋资源的URL、设置与储存 属性、应用程序初始参数,设置动态设置Servlet实例。当整个Web应用程序加载Web容器之后,容器会生成一个ServletContext对象作为整个应用程序的代表,并设置给ServletConfig,只要通过Servlet的getServletContext()方法就可以取得ServletContext对象。

tomcat服务器就是根据servlet定义加载web.xml生成servletContext对象,这个时候我的理解就是web框架需要做的就是实现一个初始化监听器,并且接收servletContext作用初始化参数:

 <listener>  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>

contextLoaderListener实现servletContextListener接口,使得tomcat在初始化加载完web.xml后调用servletContextListener的contextInitialized(ServletContextEvent)方法,spring实现contextLoaderListener在实现的contextInitialized方法中初始化spring的上下文对象用于对spring上下文的管理。

/**     * Initialize Spring's web application context for the given servlet context,     * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and     * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.     * @param servletContext current servlet context     * @return the new WebApplicationContext     * @see #CONTEXT_CLASS_PARAM     * @see #CONFIG_LOCATION_PARAM     */    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {        if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {            throw new IllegalStateException(                    "Cannot initialize context because there is already a root application context present - " +                    "check whether you have multiple ContextLoader* definitions in your web.xml!");        }        Log logger = LogFactory.getLog(ContextLoader.class);        servletContext.log("Initializing Spring root WebApplicationContext");        if (logger.isInfoEnabled()) {            logger.info("Root WebApplicationContext: initialization started");        }        long startTime = System.currentTimeMillis();        try {            // Determine parent for root web application context, if any.            ApplicationContext parent = loadParentContext(servletContext);            // Store context in local instance variable, to guarantee that            // it is available on ServletContext shutdown.            this.context = createWebApplicationContext(servletContext, parent);            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);            ClassLoader ccl = Thread.currentThread().getContextClassLoader();            if (ccl == ContextLoader.class.getClassLoader()) {                currentContext = this.context;            }            else if (ccl != null) {                currentContextPerThread.put(ccl, this.context);            }            if (logger.isDebugEnabled()) {                logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +                        WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");            }            if (logger.isInfoEnabled()) {                long elapsedTime = System.currentTimeMillis() - startTime;                logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");            }            return this.context;        }        catch (RuntimeException ex) {            logger.error("Context initialization failed", ex);            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);            throw ex;        }        catch (Error err) {            logger.error("Context initialization failed", err);            servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);            throw err;        }    }

这个时候我在想,spring的配置文件在哪里读取的?明明在web.xml文件中已经配置了。然后又去ContextLoader中找contextConfigLocation,结果有这个属性:

/**     * Name of servlet context parameter (i.e., "<code>contextConfigLocation</code>")     * that can specify the config location for the root context, falling back     * to the implementation's default otherwise.     * @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION     */    public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";

并且在创建spring上下文对象ApplicationContext的时候付给该对象:

这里wac为ConfigurableWebApplicationContext的实例,该类是spring上下文对象的接口类。

这里的refresh方法是对spring管理的bean工厂、事件广播器、消息源、事件监听器等的初始化及bean定义的加载。

    public void refresh() throws BeansException, IllegalStateException {        synchronized (this.startupShutdownMonitor) {            // Prepare this context for refreshing.            prepareRefresh();            // Tell the subclass to refresh the internal bean factory.            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();            // Prepare the bean factory for use in this context.            prepareBeanFactory(beanFactory);            try {                // Allows post-processing of the bean factory in context subclasses.                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.                onRefresh();                // Check for listener beans and register them.                registerListeners();                // Instantiate all remaining (non-lazy-init) singletons.                finishBeanFactoryInitialization(beanFactory);                // Last step: publish corresponding event.                finishRefresh();            }            catch (BeansException ex) {                // Destroy already created singletons to avoid dangling resources.                destroyBeans();                // Reset 'active' flag.                cancelRefresh(ex);                // Propagate exception to caller.                throw ex;            }        }    }

到这里springmvc的初始化工作基本完成了,第一次看框架源代码,可能有些地方理解有偏差,不对的地方,希望猿们帮忙指正,共同进步~~~

原创粉丝点击