1. 程式人生 > >【spring】原始碼分析 一 從ContextLoaderListener開始·

【spring】原始碼分析 一 從ContextLoaderListener開始·

原始碼環境 : idea + spring 4.3.4 +tomcat7 + gradle

附 : 基於 java  註解的 配置元資料 的 web.xml 配置做參考(spring 3.0 後支援)

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">


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

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            com.ycit.config.DataSourceConfig,
            com.ycit.config.AppConfig
        </param-value>
    </context-param>
    
    <servlet>
        <servlet-name>solutionServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextClass</param-name>
            <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>com.ycit.config.MvcConfig</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>solutionServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!-- 開啟 druid 監控-->
    <servlet>
        <servlet-name>DruidStatView</servlet-name>
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DruidStatView</servlet-name>
        <url-pattern>/druid/*</url-pattern>
    </servlet-mapping>

</web-app>


1.  ContextLoaderListener 簡介

★   位置 :   Spring-web 的 jar 包中 ,包路徑 : org.springframework.web.context.ContextLoaderListener

★ UML 關係圖如下  :

                 

介紹: 

引導性 監聽器,用於啟動 和 關閉 Spring 的  根 WebApplicationContext,委託(delegate)給 ContextLoader 和 ContextCleanupListener 執行。

如果配置 了 org.Springframework.web.util.Log4jConfigListener(已過時) ,則 應該 配置在 Log4jConfigListener 的後面;Spring 3.1 之後,ContextLoaderListener支援 通過建構函式 直接注入 根 WebApplicationContext ,因此允許 程式設計式 的 配置 Servlet 3.0+ 的 環境。

該類繼承了 ServletContextListener,ServletContextListener 是 servlet 中 八個 分門別類的監聽器之一 ,負責監聽 Servlet Context 的生命週期 (該生命週期其實就對應著應用的生命週期)。所以 ContextLoaderListener  就負責 監聽 Spring 的初始化和 Spring 的 消亡 。當 啟動伺服器釋出專案時,spring 初始化,觸發 ContextInitialized()方法,初始化 WebApplicationContext 物件;當關閉伺服器時,觸發 contextDestroyed ( ) 方法,銷燬  WebApplicationContext 物件 。

而主要的操作業務從 ContextLoader 類繼承而來;

2. 流程分析

初始化大致流程如下圖所示(有所省略,其中省略了 配置並且 重新整理 WebApplicationContext 方法)。

                                             

分析:

             載入 web.xml 中的配置,和 spring 相關的啟動配置包括 : ContextLoaderListener 監聽器的配置;contextClass ( 配置Spring使用的 ApplicationContext 實現類,可省略,原因見下文)以及 contextConfigLocation(配置檔案的位置,可省略,見下) 引數的配置;

             靜態程式碼塊 :應用啟動,ContextLoaderListener 及其父類 ContextLoader 開始工作 。 這裡有必要提及一下關於子父類靜態程式碼塊,建構函式的執行順序的問題 。正常的順序是 。 父類的靜態程式碼塊 → 子類的靜態程式碼塊 → 父類程式碼塊(非靜態) → 父類建構函式 → 子類程式碼塊 (非靜態) → 子類建構函式 。 所以首先執行 ContextLoader 的靜態程式碼塊 :此程式碼塊的功能是讀取 Spring 的配置檔案 ContextLoader.properties ,而該配置檔案的內容只有如下一行,為 Spring 的欄位 defaultStrategies(java.util.Properties 型別) 賦如下的鍵值對 。

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

            initWebApplicationContext  :  通過 給定的  ServletContext 初始化 Spring 的 web 應用上下文(WebApplicationContext),分別儲存在如下兩個私有欄位中:

	/**
	 * The 'current' WebApplicationContext, if the ContextLoader class is
	 * deployed in the web app ClassLoader itself.
         * volatile 為 多執行緒中用到的 關鍵字 ,作用是 保持被修飾的欄位在被讀取的時候返回的都是當前最新的,
	 */
	private static volatile WebApplicationContext currentContext;

	/**
	 * The root WebApplicationContext instance that this loader manages.
	 */
	private WebApplicationContext context; // 儲存初始化的ApplicationContext 實現類,可用於 ServletContext 消亡時 ApplicationContext關閉並釋放資源


currentContext 是指 當前 的 WebApplicationContext;

context 是指 每個 ServletContext 對應的那個 WebApplicationContext;

                           注 :  維基百科對 java 中的  volatile 介紹如下 :
Java支援volatile關鍵字,但它被用於其他不同的用途。當volatile用於一個作用域時,Java保證如下:

1.(適用於Java所有版本)讀和寫一個volatile變數有全域性的排序。也就是說每個執行緒訪問一個volatile作用域時會在繼續執行之前讀取它的當前值,而不是(可能)使用一個快取的值。(但是並不保證經常讀寫volatile作用域時讀和寫的相對順序,也就是說通常這並不是有用的執行緒構建)。
2.(適用於Java5及其之後的版本)volatile的讀和寫建立了一個happens-before關係,類似於申請和釋放一個互斥鎖。
使用volatile會比使用鎖更快,但是在一些情況下它不能工作。volatile使用範圍在Java5中得到了擴充套件,特別是雙重檢查鎖定現在能夠正確工作。

3 . 原始碼分析

 初始化原始碼分析

ContextLoader . initWebApplicationContext ()主程式碼:最終返回 一個 WebApplicationContext 的相關實現類;

// Store context in local instance variable, to guarantee that
    // it is available on ServletContext shutdown.
    /**建立相應的 WebApplicationContext 例項 begin**/
    if (this.context == null) {
        this.context = createWebApplicationContext(servletContext);
    }
    /**建立相應的 WebApplicationContext 例項 end**/
    /**設定 parent context屬性,對於多個 root WebApplicationContext 可以共享,對於單個的不需要關心parent context**/
    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);
            }
 /**設定 parent context 屬性 end**/
       // 配置 並且重新整理 WebApplicationContext,此處比較複雜
            configureAndRefreshWebApplicationContext(cwac, servletContext);
        }
    }
    //註冊 context
    servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
    /**儲存當前的應用上下文 begin**/
    ClassLoader ccl = Thread.currentThread().getContextClassLoader();
    if (ccl == ContextLoader.class.getClassLoader()) {
        currentContext = this.context;
    }
    else if (ccl != null) {
        currentContextPerThread.put(ccl, this.context);
    }
/**儲存當前的應用上下文 end**/
    return this.context;

相關類介紹:

ConfigurableWebApplicationContext 介面: WebApplicationContext  和 ConfigurableApplicationContext 的 子介面

             WebApplicationConext 介面:ApplicationContext 的子介面,為 web 應用 提供 配置(獲取 ServletContext)的介面;當應用正在執行時,是隻讀的,但是如果實現類支援的話,可以重新載入;相對於其父介面的 ApplicationContext  , 該介面提供了 獲取 ServletContext 物件的方法;

             ConfigurableApplicationContext 介面:ApplicationContext 的子介面,提供 配置 一個 應用上下文的 屬性,如設定 environment,BeanFactoryPostProcessor,ApplicationListener,ProtocolResolver 等;

附錄1: AnnotationConfigWebApplicationContext 和 XmlWebApplicationContext 的 頂層中 和 BeanFactory 相關的UML 類圖;


以上原始碼主要做了三件事:

     ① 例項化  WebApplicationContext 相關 實現類

     ② 載入並 設定父 上下文 (此處略 ,一般的 web 應用 無 父上下文,返回 null)

     ③  配置 並 重新整理 WebApplicationContext

分別分析:

 3.1   ContextLoader . createWebApplicationContext (ServletContext sc)例項化 WebApplicationContext 實現類

	protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
		Class<?> contextClass = determineContextClass(sc);
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);//例項化
	}


  ContextLoader . determineContextClass(ServletContext sc) 方法: 決定contextClass,該 contextClass 決定了  WebApplicationContext 的 實現類的型別;這裡建立的 實現類為 AnnotationConfigWebApplicationContext ;

	protected Class<?> determineContextClass(ServletContext servletContext) {
 //獲取 web.xml 中 初始化引數 contextClass,本文設定了該引數
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM); 
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader()); //使用指定的 class 反射出 Class 物件
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
 // 否則使用預設策略,即獲得 XMLWebApplicationContext 對應的bean 的名稱
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}

         3.2 載入並 設定父 上下文

         3.3   ContextLoader . configureAndRefreshWebApplicationContext(cwac, servletContext)配置並且重新整理 WebApplicationContext

	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		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
   //獲取 web.xml 中定義的  contextId 初始化值,未定義
			String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
			if (idParam != null) {
				wac.setId(idParam);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}

		wac.setServletContext(sc);//配置了 servletContext 屬性
  //獲取 web.xml 中定義的 contextConfiLocation 初始化引數值 ,已定義,
//配置了除 mvc 配置檔案的其他配置檔案路徑如 資料庫連線配置 和 spring 配置檔案
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);//配置了 configLocation 欄位屬性
		}

		// 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
  /**   初始化   應用上下文 中 和 Servlet 相關的 佔位符 屬性資源   begin  **/
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}
  /**   初始化   應用上下文 中 和 Servlet 相關的 佔位符 屬性資源   end**/
//  載入web.xml 中 自定義的 其他初始化內容,這裡都沒有定義
		customizeContext(sc, wac);
//WebApplicationContext  的重新整理
		wac.refresh();
	}

----------------------------  environment 獲取 begin---------------------------------------------------

ConfigurableWebApplicationContext . getEnvironment 方法為抽象方法;

AbstractApplicationContext . getEnvironment 為方法的實現:

	public ConfigurableEnvironment getEnvironment() {
		if (this.environment == null) {
			this.environment = createEnvironment();//呼叫 StandardEnvironment的建構函式
		}
		return this.environment;
	}
StandardEnvironment 的建構函式會先執行 父類 AbstractEnvironment 的 建構函式:

AbstractEnvironment 建構函式 及 customizePropertySources方法:

      public AbstractEnvironment() {
		customizePropertySources(this.propertySources);
		if (this.logger.isDebugEnabled()) {
			this.logger.debug(String.format(
					"Initialized %s with PropertySources %s", getClass().getSimpleName(), this.propertySources));
		}
	}

	protected void customizePropertySources(MutablePropertySources propertySources) {
	}

Note:父類 中呼叫 被子類重寫(override)的自身方法時,會執行子類的重寫方法,而不會執行父類中的方法;如果想要執行父類中的方法,需要明確呼叫 super.methodName();

所以這裡呼叫 StandardServletEnvironment 中的重寫方法:

       protected void customizePropertySources(MutablePropertySources propertySources) {
//新增 key 為 servletConfigInitParams ,value 為 Object 佔位符
		propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
//新增 key 為 servletContextInitParams,value 為 Object 佔位符
		propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
		if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
//新增 key 為 jndiProperties,value 為 Object 佔位符
			propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
		}
		super.customizePropertySources(propertySources);//執行父類 StandardEnvironment 中方法,添加了2 個
	}

StandardEnvironment 中的重寫方法:
	protected void customizePropertySources(MutablePropertySources propertySources) {
//key 為 systemProperties
		propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
//key 為 systemEnvironment
		propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
	}

getEnvironment 方法 最終返回 StandardServletEnvironment 實現類,其中的 propertySource 欄位(MutablePropertySources 類)中初始化了 5 個 PropertySource(目前前 3 個 source 都是 佔位符 object,後期會進行填充和替換);即完成了 Environment 相關實現類的 初始化;


附錄2 :StandardEnvironment 頂層父類 UML 圖



相關類介紹:

PropertySources 介面 :包含 一個 或者 多個 PropertySource 的物件;即用於 儲存;提供了 是否包含 | 獲取 property source 的 抽象方法;

           MutablePropertySources 類:PropertySources 介面 的實現類,用於 操作 屬性資源,並且 提供了可以拷貝 已存在 的 PropertySources 的 建構函式;  

PropertySource 抽象類:代表一個 資源 的抽象基類,使用鍵值對錶示;

          StubPopertySource:PropertySource 的內部靜態實現類;當一個實際的屬性資源不能在 應用上下文建立時初始化,則使用此類,此類中的 source 為 object 佔位符,後期進行替換;

          MapPropertySource:PropertySource 的 實現類,從 Map 物件中讀取 鍵 和 值,即可以通過 Map 物件 構造 PropertySource ;

          SystemEnvironmentPopertySource: MapPropertySource 的子類,特殊的 MapPropertySource,用於處理 使用 AbstractEnvironment . getSystemEnvironment 方法 獲取到的 系統環境變數;

          ServletContextPropertySource:從 一個 ServletContext 物件中 讀取 初始化引數,即 通過 ServletContext 物件構造 PropertySource;

          ServletConfigPropertySource:類同上;

ConfigurableEnvironment:Environment 型別的 配置介面,提供設定 active profiles 和 default profiles (用於不同的環境開發的不同配置)以及 操作底層屬性資源 的 設施;

          StandardEnvironment:Environment 的實現類,適合於在標準的場景下使用(如 非 web 場景);

------------------------------------  environment 獲取 end---------------------------------------------------

------------------------------------  初始化  PropertySources  begin---------------------------------------------------

ConfigurableWebEnvironment . initPropertySources 為抽象方法;

StandardServletEnvironment . initPropertySources 為方法的實現:

public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) {
		WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
	}

WebApplicationContextUtils . initServletPropertySources 方法:使用給定的 ServletContext 和 ServletConfig 物件的例項 替換 StubPropertySource 中的相關佔位符

	public static void initServletPropertySources(
			MutablePropertySources propertySources, ServletContext servletContext, ServletConfig servletConfig) {

		Assert.notNull(propertySources, "'propertySources' must not be null");
         // 替換 key 為 servletContextInitParams 的 source 值
		if (servletContext != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) &&
				propertySources.get(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
			propertySources.replace(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME,
					new ServletContextPropertySource(StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME, servletContext));
		}
        // 替換 key 為 servletConfigInitParams的 source 值
		if (servletConfig != null && propertySources.contains(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) &&
				propertySources.get(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME) instanceof StubPropertySource) {
			propertySources.replace(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME,
					new ServletConfigPropertySource(StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME, servletConfig));
		}
	}

          initPropertySources() 方法 在 下面 的  refresh() 方法 中也會呼叫到 ,這裡提前載入 是為了 確保  在 任何 的 後處理 (post-processing)或者 初始化 發生在 refresh() 之前 這兩種情況下,Servlet 屬性資源 仍然可用;

主要是將 MutablePropertySources  物件中 propertySourceList  列表中儲存的和 ServletConfig 和 ServletContext 相關的屬性 替換成 當前 環境下 的 ServletContext 和 ServletConfig(此時的 ServletConfig 為 null) ,這樣就 順利的 將 ServletContext  和 ServletConfig 中 儲存的 各種資源資訊 轉移到了 當前 應用上下文中,即 儲存在AnnotationConfigWebApplicationContext 物件下的 ConfigurableEnvironment 引數 中;

綜上,initPropertySources 方法的目的就是 將 當前的 ServletContext 和 ServletConfig 資源 載入到  WebApplicationContext 的 相關實現類的 environment 屬性中;

------------------------------------  初始化  PropertySources  end---------------------------------------------------

------------------------------------------------------------------------------------------------------------------------------------------------------------

ConfigurableApplicationContext . refresh 方法為抽象方法;

AbstractApplicationContext . refresh : 所有的 ApplicationContext 的唯一實現方法,採用了 模版方法設計模式;

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
       // 重新整理前的準備 工作:涉及屬性的設定以及屬性資源的 初始化
			prepareRefresh();

			// 通知子類重新整理 內建的 bean 工廠,獲得一個新的 bean factory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

	// 配置 工廠的 標準上下文特性,例如 上下文的 ClassLoader 和 post-processors
			prepareBeanFactory(beanFactory);

			try {
				//在 應用上下文 子類中 增加 後處理(post-processing) 的 bean 工廠
				postProcessBeanFactory(beanFactory);

				// 在應用上下文中呼叫所有 已註冊的 BeanFactoryPostProcesser 作為 bean
				invokeBeanFactoryPostProcessors(beanFactory);

				// 註冊具有攔截功能的 bean processors
				registerBeanPostProcessors(beanFactory);

				// 為應用上下文 初始化  訊息 源
				initMessageSource();

				// 為應用上下文 初始化 事件 多路廣播
				initApplicationEventMulticaster();

				// 初始化其他特殊的 bean
				onRefresh();

				// 檢查 監聽器 相關的 bean ,並註冊他們
				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();
			}
		}
	}

相關類介紹:

ConfigurableListableBeanFactory 介面 :ListableBeanFactory,ConfigurableBeanFactory,AutowireCapableBeanFactory 的子介面,

          ListableBeanFactory :提供了列舉所有 bean 例項的 方法,而不是提供名稱去定向尋找;

          ConfigurableBeanFactory:被大多數的 bean 工廠 實現的 配置介面,提供 了用於配置 bean 工廠 的 基礎設施;

          AutowireCapableBeanFactory: BeanFactory 的直接子介面,是 BeanFactory 的 擴充套件介面,能夠實現自動裝配;


重新整理工作 所做的 工作比較多 ,下面一個一個分析 :

3.3.1  AbstractApplicationContext . prepareRefresh():為重新整理 準備 context;

	protected void prepareRefresh() {
		this.startupDate = System.currentTimeMillis();
		this.closed.set(false);//context 是否 已經關閉,false 代表未關閉
		this.active.set(true);// context 當前是否是活躍的,true 代表 活躍

		if (logger.isInfoEnabled()) {
			logger.info("Refreshing " + this);
		}

		// Initialize any placeholder property sources in the context environment
		initPropertySources();//上面有呼叫過

		// Validate that all properties marked as required are resolvable
		// see ConfigurablePropertyResolver#setRequiredProperties
		getEnvironment().validateRequiredProperties();//驗證資源

		// Allow for the collection of early ApplicationEvents,
		// to be published once the multicaster is available...
		this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
	}

AbstractApplicationContext . initPropertySources 方法:空方法,由不同的子類進行不同的實現;這裡再次初始化 屬性資源方法 ,但是此時 ServletContextPropertySource 已經 成功加入到了 MutablePropertySources  物件的 propertySourceList  列表中;

------------------------------------  property 驗證 begin---------------------------------------------------

ConfigurableEnvironment . validateRequiredProperties 為抽象方法;

AbstractEnvironment . validateRequiredProperties 為實現方法:

      private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);

       private final ConfigurablePropertyResolver propertyResolver =
			new PropertySourcesPropertyResolver(this.propertySources);

       public void validateRequiredProperties() throws MissingRequiredPropertiesException {
		this.propertyResolver.validateRequiredProperties();
	}

PopertySourcesPropertyReolver . validateRequiredProperties 方法:
public void validateRequiredProperties() {
		MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
		for (String key : this.requiredProperties) {
			if (this.getProperty(key) == null) {
				ex.addMissingRequiredProperty(key);
			}
		}
		if (!ex.getMissingRequiredProperties().isEmpty()) {
			throw ex;
		}
	}

------------------------------------  property 驗證 end---------------------------------------------------

  綜上,prepareRefresh()方法用於重新整理前開啟  AbstractApplicationContext 中的開關欄位(close | active)、 environment 資源 的初始化和驗證以及初始化 earlyApplicationEvents ;都是準備工作;

3.3.2 AbstractApplicationContext . obtainFreshBeanFactory():返回一個 新的 ConfigurableListableBeanFactory   bean 工廠類

	protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
    /**  template method 模式:不同的子類有不同的實現  begin**/
		refreshBeanFactory();
		ConfigurableListableBeanFactory beanFactory = getBeanFactory(); // 將上面得到的 bean 工廠返回
    /**  template method 模式:不同的子類有不同的實現  end**/
		if (logger.isDebugEnabled()) {
			logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
		}
		return beanFactory;
	}

AbstractApplicationContext . refreshBeanFactory 為 抽象方法:使用了 模版方法設計模式,參看【design pattern】Template method(模板方法設計模式) 中的分析;

AbstractRefreshableApplicationContext . refreshBeanFactory 實現:

	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();//銷燬 bean 工廠管理的所有 bean
			closeBeanFactory(); //關閉 bean 工廠
		}
   /**  重新建立一個 新的 bean 工廠 begin **/
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory; //儲存建立的 bean 工廠 物件
			}
   /**  重新建立一個 新的 bean 工廠 end **/
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}

這裡的重新整理 bean 工廠 邏輯:如果 beanFactory 屬性不為空,則先關閉,然後再構造一個新的 DefaultListableBeanFactory;

------------------------------------  createBeanFactory   begin---------------------------------------------------

AbstractRefreshableApplicationContext . createBeanFactory()方法:通過 呼叫  DefaultListableBeanFactory 建構函式例項化 beanFactory,在呼叫過程中會呼叫 其父類 AbstractAutowireCapableBeanFactory 的 無參建構函式,如下:這裡配置了需要忽略的依賴介面,儲存在其下的  ignoredDependencyInterfaces 欄位中

        public AbstractAutowireCapableBeanFactory() {
		super();
		ignoreDependencyInterface(BeanNameAware.class); //忽略因為自動注入的 依賴介面
		ignoreDependencyInterface(BeanFactoryAware.class);
		ignoreDependencyInterface(BeanClassLoaderAware.class);
	}

	public void ignoreDependencyInterface(Class<?> ifc) {
		this.ignoredDependencyInterfaces.add(ifc);
	}


建立 DefaultListableBeanFactory 過程中 配置了  ignoredDependencyInterfaces 屬性(增加3個);

------------------------------------  createBeanFactory    end---------------------------------------------------

------------------------------------  customizeBeanFactory     begin---------------------------------------------------

AbstractRefreshableApplicationContext . customizeBeanFactory() 方法:  將 Context 上下文中的引數屬性傳遞給 bean 工廠;包括 allowBeanDefinitionOverriding   和 allowCircularReferences 屬性值(均為 boolean 值)
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
		if (this.allowBeanDefinitionOverriding != null) {
			beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		if (this.allowCircularReferences != null) {
			beanFactory.setAllowCircularReferences(this.allowCircularReferences);
		}
	}

用於將 ApplicationContext 中的 部分屬性資訊 傳遞給 剛初始化的 beanFactory ;

------------------------------------  customizeBeanFactory    end---------------------------------------------------

------------------------------------ loadBeanDefinitions      begin---------------------------------------------------

 AbstractRefreshableApplicationContext . loadBeanDefinitions 為 抽象方法  ;

AnnotationConfigWebApplicationContext . loadBeanDefinitions 實現方法(不同的子類有不同的實現方法):

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
// 通過 bean 工廠例項化 bean 定義的 reader,並在bean 工廠中註冊 相關 的 註解的 post processors
		AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory); 
//通過 bean 工廠例項化 bean 定義的掃描器
		ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
//返回當前類持有的  bean 名稱生成器,此時為null
		BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
		if (beanNameGenerator != null) {
			reader.setBeanNameGenerator(beanNameGenerator);
			scanner.setBeanNameGenerator(beanNameGenerator);
			beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
		}
// 返回當前類持有的 bean 定義 範圍解析器,此時為 null
		ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
		if (scopeMetadataResolver != null) {
			reader.setScopeMetadataResolver(scopeMetadataResolver);
			scanner.setScopeMetadataResolver(scopeMetadataResolver);
		}

		if (!this.annotatedClasses.isEmpty()) {
			if (logger.isInfoEnabled()) {
				logger.info("Registering annotated classes: [" +
						StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
			}
			reader.register(this.annotatedClasses.toArray(new Class<?>[this.annotatedClasses.size()]));
		}

		if (!this.basePackages.isEmpty()) {
			if (logger.isInfoEnabled()) {
				logger.info("Scanning base packages: [" +
						StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
			}
			scanner.scan(this.basePackages.toArray(new String[this.basePackages.size()]));
		}
//  web.xml 中配置的配置檔案路徑,spring 配置檔案和 資料庫配置檔案,程式設計式的配置
		String[] configLocations = getConfigLocations();
		if (configLocations != null) {
			for (String configLocation : configLocations) {
				try {
//獲取每個 java 檔案的 Class 物件,並利用 reader 註冊
					Class<?> clazz = getClassLoader().loadClass(configLocation);
					if (logger.isInfoEnabled()) {
						logger.info("Successfully resolved class for [" + configLocation + "]");
					}
					reader.register(clazz);
				}
				catch (ClassNotFoundException ex) {
					if (logger.isDebugEnabled()) {
						logger.debug("Could not load class for config location [" + configLocation +
								"] - trying package scan. " + ex);
					}
					int count = scanner.scan(configLocation);
					if (logger.isInfoEnabled()) {
						if (count == 0) {
							logger.info("No annotated classes found for specified class/package [" + configLocation + "]");
						}
						else {
							logger.info("Found " + count + " annotated classes in package [" + configLocation + "]");
						}
					}
				}
			}
		}
	}

相關類介紹:

AnnotatedBeanDefinitionReader : 用於 程式設計式註冊 已註解 bean    的 方便介面卡,需要提供 BeanDefinitionRegistry 類 構造物件,註冊的是 BeanDefinitionRegisty 中 的 beanDefinition;該類 是  ClassPathBeanDefininationScanner 的 一個替代品,使用 相同的 註解策略但是隻顯示的註冊類;
         ClassPathBeanDefininationScanner : 一個 bean 定義的 掃描器 ,用於檢查 classpath 下 符合條件的bean ,使用給定的記錄器 BeanFactory 或者 ApplicationContext 註冊 相關的 bean 定義;符合條件的 類 是 通過 配置 型別過濾器來偵測的,預設的過濾器包括 註解了 Spring 的 Component,Repository,Service,Controller 的 類,而且也支援 Java EE 6 的 ManagedBean 註解 和 JSR-330 的 Named 註解;

-------------------------     第 1 層     --------------------------

AnnotationConfigWebApplicationContext . getAnnotatedBeanDefinitionReader 方法:

	protected AnnotatedBeanDefinitionReader getAnnotatedBeanDefinitionReader(DefaultListableBeanFactory beanFactory) {
		return new AnnotatedBeanDefinitionReader(beanFactory, getEnvironment());
	}

-------------------------     第 2 層     --------------------------

呼叫如下的建構函式:

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry); //註冊相關處理器
	}

相關類:

BeanDefinitionRegistry : 處理 BeanDefinition 的介面,包括註冊,移除,獲取,判斷是否包含等操作,例如處理 RootBeanDefinition 和 ChildBeanDefinition; Spring 的 BeanDefinitionReader 需要 通過 該介面的 實現類 來構造,在 Spring core 中 已知的實現者 是  DefaultListableBeanFactory 和 GenericApplicationContext ;

-------------------------     第 3 層     --------------------------
AnnotationConfigUtils . registerAnnotationConfigProcessors() 方法:註冊 registry 中 所有相關的 註解 後 處理器(post processors)

	public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
		registerAnnotationConfigProcessors(registry, null);
	}
-------------------------     第 4 層     --------------------------
AnnotationConfigUtils . registerAnnotationConfigProcessors  過載(overload)方法:
         public static final AnnotationAwareOrderComparator INSTANCE = new AnnotationAwareOrderComparator();


         public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, Object source) {
// DefaultListableBeanFacotry 為 BeanDefinitionRegistry 的子類,向下轉型,轉為 DefaultListableBeanFactory
		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
// 設定bean 工廠的 dependencyComparator 屬性,對依賴的列表和陣列提供可選的排序
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
// 設定 bean 工廠的 autowireCandidateResolver 屬性,用來檢查 一個 bean 定義是否需要自動注入 的 解析器
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<BeanDefinitionHolder>(4);
// bean 工廠的 beanDefinitionMap 欄位中是否包含bean 定義:
//org.springframework.context.annotation.internalConfigurationAnnotationProcessor,不包含則註冊
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
//是否包含 org.springframework.context.annotation.internalAutowiredAnnotationProcessor
		if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
//是否包含 org.springframework.context.annotation.internalRequiredAnnotationProcessor,不包含則註冊
		if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
//是否包含 org.springframework.context.annotation.internalCommonAnnotationProcessor
		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
//是否包含 org.springframework.context.annotation.internalPersistenceAnnotationProcessor
		// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
		if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition();
			try {
				def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
						AnnotationConfigUtils.class.getClassLoader()));
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
			}
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
//是否包含 org.springframework.context.event.internalEventListenerProcessor
		if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
		}
//是否包含org.springframework.context.event.internalEventListenerFactory
		if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
		}

		return beanDefs;
	}

註解處理器詳情:

org.springframework.context.annotation.internalConfigurationAnnotationProcessor : 內部管理 Configuration 註解處理器 的 bean 的 名稱;即ConfigurationClassPostProcessor類;

org.springframework.context.annotation.internalAutowiredAnnotationProcessor:內部管理 Autowired 註解處理器 的 bean 的名稱;即AutowiredAnnotationBeanPostProcessor 類;

org.springframework.context.annotation.internalRequiredAnnotationProcessor:內部管理 Required 註解處理器 的 bean 的名稱;即RequiredAnnotationBeanPostProcessor
類;

org.springframework.context.annotation.internalCommonAnnotationProcessor:內部管理  JSR-250 註解處理器 的 bean 的名稱;即CommonAnnotationBeanPostProcessor 類;

org.springframework.context.annotation.internalPersistenceAnnotationProcessor:內部管理  JPA 註解處理器 的 bean 的名稱  , 沒有使用 JPA類庫,不會載入;即PersistenceAnnotationBeanPostProcessor類;

org.springframework.context.event.internalEventListenerProcessor:內部管理 @EventListener 註解 處理器 的 bean 的名稱;即EventListenerMethodProcessor類;

org.springframework.context.event.internalEventListenerFactory:內部管理 EventListenerFactory 的 bean 的名稱;即DefaultEventListenerFactory類;

相關類介紹:

DefualtListableBeanFactory: AbstractAutowireCapbleBeanFactory ,ConfigurableListableBeanFactory,BeanDefinitionRegistry 的實現類;一個 基於 bean 定義物件 的完全成熟的 bean 工廠;通常的使用方法是:首先 註冊所有 的 beanDefinition(可能從 bean 定義 檔案中 讀取),

BeanDefinition 介面:一個 BeanDefinition 描述了一個 bean 的例項,包括 屬性值,建構函式引數值,以及 更多的 資訊

       AnnotatedBeanDefinition:BeanDefinition 的抽象類;提供 AnnotationMetadata 類 的 獲取方法,不需要保證類已經載入;

       AbstractBeanDefinition:BeanDefinition 的抽象類

                 RootBeanDefinition 實現類: 支援通過 類的 Class 物件 建立 bean 定義,適用於註冊 單獨的 bean 定義;

                 GenericBeanDefinition 實現類:在 父 介面的基礎上 增加 了 parentName 引數 ;通常情況下使用該類 註冊 bean ,可以靈活的配置 父 名稱;

                          AnnotatedGenericBeanDefinition:實現了 AnnotatedBeanDefinition ,繼承了 GenericBeanDefinition,GenericBeanDefiniton 類的擴充套件,通過 AnnotatedBeanDefinition 介面 增加對 給定註解元資料的支援,通過 Class 陣列 或者 AnnotationMetadata 或者 MethodMetadata 構造;

BeanDefinitionHolder 類: BeanMetadataElement 的實現類,持有  一個 包含了 名稱 和 別名(aliases)的 BeanDefinition,可以註冊為一個 內部 bean 的佔位符;

AnnotationMetadata:定義 對指定類註解的 訪問 ;可以在類未載入的時候訪問;

Comparator:jdk 的 用於比較功能的類;

       OrderComparator :spring 中 對 Comparator 的實現,用於物件的排序

  AnnotationAwareOrderComparator:是 OrderComparator 的一個擴充套件,支援 Spring 的 Ordered 介面 以及 @Order 註解 和 @Priority 註解

AutowireCandidateResolver:決定 一個 bean 定義 是否需要 自動注入 的 策略介面;

       ContextAnnotationAutowireCandidateResolver:實現了 AutowireCandidateResolver,支援 註解 和 @Lazy 的 惰性 註解方法;

-------------------------     第 5 層     --------------------------

AnnotationConfigUtils . registerPostProcessor()方法:註冊 後處理器, 返回 BeanDefinitionHolder 物件

	private static BeanDefinitionHolder registerPostProcessor(
			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

		definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(beanName, definition);
		return new BeanDefinitionHolder(definition, beanName);
	}

-------------------------     第 6 層     --------------------------

BeanDefinitionRegistry . registerBeanDefinition()抽象方法

DefaultListableBeanFactory . registerBeanDefinition實現方法:向 bean 工廠中註冊 bean 的 定義;實際上是以鍵值對的形式新增到 beanDefinitionMap 的欄位中,同時維護 beanDefinitonName 欄位 和 manualSinglethonNames;

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();//驗證 bean 定義
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		BeanDefinition oldBeanDefinition;
// 檢查該 beanDefinition 是否已經存在
		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) {
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
						"': There is already [" + oldBeanDefinition + "] bound.");
			}
			else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (this.logger.isWarnEnabled()) {
					this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							oldBeanDefinition + "] with [" + beanDefinition + "]");
				}
			}
			else if (!beanDefinition.equals(oldBeanDefinition)) {
				if (this.logger.isInfoEnabled()) {
					this.logger.info("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			else {
				if (this.logger.isDebugEnabled()) {
					this.logger.debug("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + oldBeanDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
// 工廠的 bean建立階段是否已經開始
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				synchronized (this.beanDefinitionMap) {
					this.beanDefinitionMap.put(beanName, beanDefinition);
					List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
					updatedDefinitions.addAll(this.beanDefinitionNames);
					updatedDefinitions.add(beanName);
					this.beanDefinitionNames = updatedDefinitions;
					if (this.manualSingletonNames.contains(beanName)) {
						Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
						updatedSingletons.remove(beanName);
						this.manualSingletonNames = updatedSingletons;
					}
				}
			}
//仍然處於 啟動註冊階段
			else {
				// Still in startup registration phase
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		if (oldBeanDefinition != null || containsSingleton(beanName)) {
//重置所有 beanName 相關 bean definition 快取
			resetBeanDefinition(beanName);
		}
	}

DefaultListableBeanFactory 中欄位介紹:

           beanDefinitionMap: bean 定義 物件的 Map 集合,通過 bean 名稱 鍵入;

           beanDefinitionNames:bean 定義 名稱的 list 集合,

           manualSingletonNames:手動註冊的單例的名稱的 list 集合;

所以,AnnotatedBeanDefinitionReader 建構函式的內部 使用工具類 為 beanFactory  註冊了註解相關的 bean 定義,以及功能類;說白了就是,配置bean 工廠如下的幾個欄位: dependencyComparator ,autowireCandidateResolver,beanDefinitionMap,beanDefinitionNames,manualSingletonNames;返回的 reader 內建了 registry 和 environment ;

附錄3 :DefualtListableBeanFactory 上層關係圖


-------------------------     第 1 層     --------------------------

 ClassPathBeanDefinitionScanner  例項化,其內部呼叫 ClassPathBeanDefinitionScanner 的構造器 ,同時呼叫了父類 ClassPathScanningCandidateComponentProvider 的構造器,如下:

	protected ClassPathBeanDefinitionScanner getClassPathBeanDefinitionScanner(DefaultListableBeanFactory beanFactory) {
		return new ClassPathBeanDefinitionScanner(beanFactory, true, getEnvironment());
	}

-------------------------     第 2 層     --------------------------

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters, Environment environment) {
		super(useDefaultFilters, environment);

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		this.registry = registry;

		// Determine ResourceLoader to use.
		if (this.registry instanceof ResourceLoader) {
			setResourceLoader((ResourceLoader) this.registry);
		}
	}

-------------------------     第 3 層     --------------------------
	public ClassPathScanningCandidateComponentProvider(boolean useDefaultFilters, Environment environment) {
		if (useDefaultFilters) {
			registerDefaultFilters();//註冊過濾器
		}
		Assert.notNull(environment, "Environment must not be null");
		this.environment = environment;
	}

-------------------------     第 4 層     --------------------------

其中的 registerDefaultFilters() 方法:註冊預設的過濾器

        protected void registerDefaultFilters() {
// 為 @Component註解註冊 預設過濾器 ,這將隱式的註解所有包含 Component 元註解的註解
//包括 Repository 註解, Service註解,Controller註解
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
//如果專案中載入了相關 jar 包,則會為 JSR-250 註冊過濾器
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
			logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
		}
		try {
//如果專案中載入了相關 jar 包,則會為 JSR-330 註冊過濾器
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
			logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}

AnnotationTypeFilter 類:TypeFilter 的間接實現類,作用是 使用 給定的註解 匹配 類 的 簡單 過濾器,也會 檢查 通過 繼承得到的註解;通過 給定的註解的型別 例項化;

綜上,ClassPathBeanDefinitionScanner  例項化的內部 一定會註冊一個 過濾 @Component 註解的 AnnotationTypeFilter,嘗試註冊 過濾 JSR-250 註解(ManagedBean)的 AnnotationTypeFilter 和 JSR-330 註解(Named)的 AnnotationTypeFilter;說白了就是 配置 beanFactory 的 includeFilters 欄位;返回的 scanner 內建了 registry 和 environment

-------------------------     第 1 層     --------------------------

BeanNameGenerator 例項化:返回自定義的 BeanNameGenerator,此處為 null;給 AnnotatedBeanDefinitionReader 類 和 ClassPathBeanDefinitionScanner 類 使用

	protected BeanNameGenerator getBeanNameGenerator() {
		return this.beanNameGenerator;
	}

BeanNameGenerator : 為 bean 定義 生成 bean 名稱的 策略 介面,初始化時獲取為空

-------------------------     第 1 層     --------------------------

DefaultListableBeanFactory . registerSingleton 方法:向  beanFactory 中  新增 手動註冊的單例,維護  beanFactory 的 manualSingletonNames ,singletonObjects,singletonFactories,earlySingletonObjects,registeredSingletons 欄位;

        public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		super.registerSingleton(beanName, singletonObject);

		if (hasBeanCreationStarted()) {
			// Cannot modify startup-time collection elements anymore (for stable iteration)
			synchronized (this.beanDefinitionMap) {
				if (!this.beanDefinitionMap.containsKey(beanName)) {
					Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames.size() + 1);
					updatedSingletons.addAll(this.manualSingletonNames);
					updatedSingletons.add(beanName);
					this.manualSingletonNames = updatedSingletons;
				}
			}
		}
		else {
			// Still in startup registration phase
			if (!this.beanDefinitionMap.containsKey(beanName)) {
				this.manualSingletonNames.add(beanName);
			}
		}

		clearByTypeCache();
	}

super . registerSingleton 方法 是 DefaultSingletonBeanRegistry . registerSingleton 方法:
	public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
		Assert.notNull(beanName, "'beanName' must not be null");
		synchronized (this.singletonObjects) {
			Object oldObject = this.singletonObjects.get(beanName);
			if (oldObject != null) {
				throw new IllegalStateException("Could not register object [" + singletonObject +
						"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
			}
			addSingleton(beanName, singletonObject);
		}
	}
// 維護了 beanFactory 中的多個欄位
	protected void addSingleton(String beanName, Object singletonObject) {
		synchronized (this.singletonObjects) {
			this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
			this.singletonFactories.remove(beanName);
			this.earlySingletonObjects.remove(beanName);
			this.registeredSingletons.add(beanName);
		}
	}

-------------------------     第 1層     --------------------------

ScopeMetadataResolver 例項化:返回自定義的 ScopeMetadataResolver 類,此時為 null,給 AnnotatedBeanDefinitionReader 類 和 ClassPathBeanDefinitionScanner 類使用;

	protected ScopeMetadataResolver getScopeMetadataResolver() {
		return this.scopeMetadataResolver;
	}


ScopeMetadataResolver: 為 bean 定義 解析 範圍 的 策略介面

-------------------------     第 1 層     --------------------------

AnnotatedBeanDefinitionReader . register 方法

	public void register(Class<?>... annotatedClasses) {
		for (Class<?> annotatedClass : annotatedClasses) {
			registerBean(annotatedClass);
		}
	}

	public void registerBean(Class<?> annotatedClass) {
		registerBean(annotatedClass, null, (Class<? extends Annotation>[]) null);
	}

	public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

相關類介紹:

ScopeMetadata:描述 Spring 管理 的 bean 的 作用域,包括 作用域的 名稱 和  代理作用域的行為,預設的作用域為 singleton,預設 的代理作用域是 不代理;

AnnotationMetadata:介面,定義 對指定類註解的 訪問 ;可以在類未載入的時候訪問;

        StandardAnnotationMetadata:實現類,使用標準的反射反射一個 給定的類;

ScopeMetadataResolver:解析 bean 定義 的 作用域 的策略介面;

ScopedProxyMode:各種 代理作用域的值 的 列舉 :

             default  : default 通常 等於 no ,除非 配置了不同的 default

              no : 不建立 作用域代理

              interfaces:建立 JDK 動態代理

              target_class:建立 基於 一個類的 代理(使用 CGLIB)

-------------------------     第 2 層     --------------------------

AnnotatedGenericBeanDefinition 例項化:

	public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
		setBeanClass(beanClass);
		this.metadata = new StandardAnnotationMetadata(beanClass, true);
	}

-------------------------     第 3 層     --------------------------

StandardAnnotationMetadata 例項化:初始化 欄位資訊;

	public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
		super(introspectedClass);
		this.annotations = introspectedClass.getAnnotations();//獲得類上的註解
		this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
	}

-------------------------     第 2 層     --------------------------

AnnotationScopeMetadataResolver . resolveScopeMetadata