【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關鍵字,但它被用於其他不同的用途。當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 抽象類:代表一個 資源 的抽象基類,使用鍵值對錶示;
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---------------------------------------------------
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 集合;
附錄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