首頁 >Java >java教程 >分析spring web啟動時IOC源碼

分析spring web啟動時IOC源碼

高洛峰
高洛峰原創
2017-03-12 09:40:081579瀏覽

這篇文章分析spring web啟動時IOC源碼研究

  1. 研究IOC首先創建一個簡單的web項目,在web.xml#中我們都會加上這麼一句

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>

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

這代表了web容器啟動的時候會先進入ContextLoaderListener這個類,並且之後會去載入classpath下的applicationContext.xml檔。那麼重點就在ContextLoaderListener上,點開源碼:

/**
     * Initialize the root web application context.     */
    @Override    public void contextInitialized(ServletContextEvent event) {
        initWebApplicationContext(event.getServletContext());
    }    /**
     * Close the root web application context.     */
    @Override    public void contextDestroyed(ServletContextEvent event) {
        closeWebApplicationContext(event.getServletContext());
        ContextCleanupListener.cleanupAttributes(event.getServletContext());
    }

裡面主要為ServletContextListener介面的兩個實作方法。 web容器會先呼叫contextInitialized方法,傳入tomcat封裝的容器資源,之後呼叫父類別的初始化容器方法。

/*** The root WebApplicationContext instance that this loader manages.*/private WebApplicationContext context;public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
      ...........省略// Store context in local instance variable, to guarantee that            // it is available on ServletContext shutdown.
            if (this.context == null) {                this.context = createWebApplicationContext(servletContext);
            }            if (this.context instanceof ConfigurableWebApplicationContext) {
                ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;                if (!cwac.isActive()) {                    // The context has not yet been refreshed -> provide services such as                    // setting the parent context, setting the application context id, etc
                    if (cwac.getParent() == null) {                        // The context instance was injected without an explicit parent ->                        // determine parent for root web application context, if any.
                        ApplicationContext parent = loadParentContext(servletContext);
                        cwac.setParent(parent);
                    }
                    configureAndRefreshWebApplicationContext(cwac, servletContext);
                }
            }
            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);
            }
  ......省略            return this.context;
        
    }

這個方法裡主要步驟createWebApplicationContext方法用來建立XmlWebApplicationContext這個root根容器,這個容器就是取自servletContextEvent。

loadParentContext方法用來載入父容器。主要方法configureAndRefreshWebApplicationContext用來設定和刷新root容器,在方法內最主要的就是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.
            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) {
                logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);                // Destroy already created singletons to avoid dangling resources.                destroyBeans();                // Reset &#39;active&#39; flag.                cancelRefresh(ex);                // Propagate exception to caller.
                throw ex;
            }
        }
    }

prepareRefresh方法用來準備之後需要用到的環境。

obtainFreshBeanFactory方法取得beanFactory

@Override    protected final void refreshBeanFactory() throws BeansException {        if (hasBeanFactory()) {
            destroyBeans();
            closeBeanFactory();
        }        try {
            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);
        }
    }

實際傳回的beanFactory為其實作類別DefaultListableBeanFactory,實例化該類別用來為之後裝載xml中實例化的類別。

loadBeanDefinitions為重要的方法,用來真正的載入類別了,之前的都是準備工作


以上是分析spring web啟動時IOC源碼的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn