Spring容器建立源碼解析

img

前言

  這篇博客是對Spring(5.0.7)的ioc容器建立過程的解析,也是博主不斷debug幾天的成果。內容可能有點多,講的也可能比較枯燥。不過我相信個人分析對你們理解spring容器的整個工做原理仍是有一些幫助的。php

無參構造器:

  先是調用它的無參構造函數,初始化一些信息。
  無參構造函數中newAnnotatedBeanDefinitionReaderClassPathBeanDefiitionScanner賦值給readercontext的scanner屬性。java

newAnnotatedBeanDefinitionReader對象:

    將該容器對象做爲BeanDefinitionRegistry賦值給registry屬性,而且new了一個ConditionEvaluator賦值給conditionEvaluator屬性。以後調用registerAnnotationConfigProcessors方法將全部的annotation處理器註冊進容器。web

new ConditionEvaluator:

    這是spring對該類的描述Internal class used to evaluate {@link Conditional} annotations.。能夠看出這個類是@Conditional註解的一個解析器。在建立該類的時候利用deduceBeanFactory給該對象初始化了一個DefaultListableBeanFactory,而且該類是從容器中獲取的。spring

img

AnnotationConfigUtils.registerAnnotationConfigProcessors:

    該方法先是給容器的beanFactory初始化了private Comparator<Object> dependencyComparator;private AutowireCandidateResolver autowireCandidateResolver兩個屬性;他們分別是用於bean的排序和解析自動注入@Autowired的;以後便開始註冊一些spring內部的bean對象: 緩存

//spring檢查容器中是否注入了這些bean 沒有就建立簡單的含有基本信息的BeanDefiintion對象註冊
    // The bean name of the internally managed Configuration annotation processor.
	public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";
	// The bean name of the internally managed Autowired annotation processor.
	public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalAutowiredAnnotationProcessor";
	// The bean name of the internally managed Required annotation processor.
	public static final String REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalRequiredAnnotationProcessor";
	// The bean name of the internally managed JSR-250 annotation processor.
	public static final String COMMON_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalCommonAnnotationProcessor";
	// The bean name of the internally managed JPA annotation processor.
	public static final String PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME =
			"org.springframework.context.annotation.internalPersistenceAnnotationProcessor";
	private static final String PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME =
			"org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor";
	// The bean name of the internally managed @EventListener annotation processor.
	public static final String EVENT_LISTENER_PROCESSOR_BEAN_NAME =
			"org.springframework.context.event.internalEventListenerProcessor";
	// The bean name of the internally managed EventListenerFactory.
	public static final String EVENT_LISTENER_FACTORY_BEAN_NAME =
			"org.springframework.context.event.internalEventListenerFactory";
			
    //註冊過程以下 詳見DefaultListableBeanFactory的registerBeanDefinition
    	if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				//do some thing .... 
			}
		}
		BeanDefinition oldBeanDefinition;
		 // get beanDefinintion from cache
		oldBeanDefinition = this.beanDefinitionMap.get(beanName);
		if (oldBeanDefinition != null) { 
		    // if cache alredy has this beanName beanDefinition break
		    // some warn message or throw exception
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {
		// determine if create bean has started
		//(判斷方法很簡單benaFactory中的Set<String>alreadyCreated是否已經被填充過)
			if (hasBeanCreationStarted()) { 
            //lock beanDefinitionMap and put this beanDefinition to map
            //這裏有個小細節他在添加元素進beanDefinitionNames時是直接建立了一個原先cache size+1的list
            //而後再將this beanDefinition name 放入list,最終改變beanDefinitionNames的爲新建立list
            //if this beanDefinition is in manualSingletonNames,remove from list. why?
			}
			else {
				this.beanDefinitionMap.put(beanName, beanDefinition);
				this.beanDefinitionNames.add(beanName);
				this.manualSingletonNames.remove(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}
		if (oldBeanDefinition != null || containsSingleton(beanName)) {
		// 若是這個bean已經存在了單實例的對象則將其銷燬
			resetBeanDefinition(beanName);
		}
複製代碼

    至此AnnotatedBeanDefinitionReaderd對象建立完成markdown

newClassPathBeanDefinitionScanner對象:

    先是調用這個構造方法:app

img

    這裏能夠看出有3步操做 registerDefaultFilters, setEnvironment, setResourceLoader

registerDefaultFilters方法:

    從名字咱們不難看出這是建立默認過濾器的方法;
    其實是往該對象中添加了一個匹配@Component註解的AnnotationTypeFilter。spring對該類的解釋以下:
    A simple filter which matches classes with a given annotation,checking inherited annotations as well.框架

//代碼以下:
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
		}
		try {
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
		}
複製代碼
setEnvironment方法:

    同樣看名字咱們就能知道這是設置環境信息的。就是將以前建立AnnotatedBeanDefinitionReader對象時獲取的StandardEnvironment設置給該對象的environment屬性。異步

setResourceLoader方法:

    該方法分別給該對象的resourcePatternResolver,metadataReaderFactory,componentsIndex屬性初始化。resourcePatternResolver對象其實就是容器對象.... metadataReaderFactory是一個從容器resourceCaches屬性拷貝過來的ConcurrentHashMapresourcePatternResolver多是在加載META-INF/spring.components這個配置文件吧。具體我也不太清楚。
    至此spring容器的無參構造函數終於時調用完成了(😓)這只是簡單的一步並且不少地方即便是知道了它在幹什麼仍是不清楚他爲何這麼作若是有更瞭解的大佬還望指教編輯器

register:

  將Config類註冊進來,其實就是調用以前建立的AnnotatedBeanDefinitionReader對象的register方法將咱們所傳入的配置類註冊到容器當中。咱們能夠直接看AnnotatedBeanDefinitionReader對象的doRegisterBean方法:
  該方法先是建立了Config對象的定義信息AnnotatedGenericBeanDefinition。以後調用如下方法shouldSkip,resolveScopeMetadata,generateBeanName,processCommonDefinitionAnnotations,applyScopedProxyMode,registerBeanDefinition

img

shouldSkip方法:

    該方法先經過isAnnotated判斷有沒有@Conditional註解若是有則判斷該類是否符合注入要求。
     咱們先來看下他是如何判斷有沒有該註解的:
    首先是searchWithGetSemantics方法來查出該類全部註解。searchWithGetSemanticsInAnnotations來作判斷。若是該註解不是java包中的註解。則判斷它是不是@Conditional註解或者任什麼時候候都忽略的process。以後遞歸調用searchWithGetSemantics來看元註解有沒有包含@Conditional的。如下爲判斷源碼:

Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
	if (currentAnnotationType == annotationType ||
			currentAnnotationType.getName().equals(annotationName) ||
			processor.alwaysProcesses()) {
		T result = processor.process(element, annotation, metaDepth);
		if (result != null) {
			if (processor.aggregates() && metaDepth == 0) {
				processor.getAggregatedResults().add(result);
			}
			else {
				return result;
			}
		}
	}
	// Repeatable annotations in container?
	else if (currentAnnotationType == containerType) {
		for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
			T result = processor.process(element, contained, metaDepth);
			if (result != null) {
				// No need to post-process since repeatable annotations within a
				// container cannot be composed annotations.
				processor.getAggregatedResults().add(result);
			}
		}
	}
}
複製代碼

resolveScopeMetadata方法:

    獲取該bean的scope(這裏就不細講spring bean的做用域了不懂的自行百度),ScopeMetadata對象的值默認爲singleton,因此若是該類沒有@Scope註解默認爲單例的。

generateBeanName方法:

    獲取該bean的@Component註解標註的beanName,若是沒有默認爲類sortName。 獲取類上的@Component註解步驟與第一步時獲取@Conditional註解相似(遞歸獲取註解-排除java註解)這裏就不細講了。

processCommonDefinitionAnnotations方法:

    對@Lazy,@Primary,@DependsOn,@Role,@Description的解析(這裏提一下若是@Lazy沒有的話默認是false,以前看到有人說默認懶加載顯然時不正確的~)。豐富beanDefinition。比較簡單不詳細分析了,貼下源碼:

 AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
 if (lazy != null) {
 abd.setLazyInit(lazy.getBoolean("value"));
 }
 else if (abd.getMetadata() != metadata) {
 lazy = attributesFor(abd.getMetadata(), Lazy.class);
 if (lazy != null) {
 abd.setLazyInit(lazy.getBoolean("value"));
 }
 }
 if (metadata.isAnnotated(Primary.class.getName())) {
 abd.setPrimary(true);
 }
 AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
 if (dependsOn != null) {
 abd.setDependsOn(dependsOn.getStringArray("value"));
 }
 if (abd instanceof AbstractBeanDefinition) {
 AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
 AnnotationAttributes role = attributesFor(metadata, Role.class);
 if (role != null) {
 absBd.setRole(role.getNumber("value").intValue());
 }
 AnnotationAttributes description = attributesFor(metadata, Description.class);
 if (description != null) {
 absBd.setDescription(description.getString("value"));
 }
 }
複製代碼

applyScopedProxyMode方法:

    判斷是否須要建立代理對象。若是須要調用ScopedProxyCreator.createScopedProxy方法建立。(待補全代理對象的建立過程...)

registerBeanDefinition方法:

    從方法名能夠看出這部是真正的註冊beanDefinition。真正調用的是容器中的BeanFactory(這裏是DefaultListableBeanFactory)的registerBeanDefinition方法。首先驗證beanDefinition的信息(具體我也沒看懂在幹什麼)。以後判斷該beanDefinition是否被註冊過(若註冊過符合條件覆蓋以前的beanDefinition)。以後就是第一次註冊該bean的操做(和調用無參構造函數註冊過程一致詳情。)     

register方法分析到這裏就結束了,其實作的事情就是將配置類註冊到容器當中。

refresh:

  refresh是最重要的一步,進行了容器刷新以及bean建立。執行步驟比較多。

 prepareRefresh();
 // Tell the subclass to refresh the internal bean factory.
 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
 // Prepare the bean factory for use in this context.
 prepareBeanFactory(beanFactory);
 try {
 // Allows post-processing of the bean factory in context subclasses.
 postProcessBeanFactory(beanFactory);
 // Invoke factory processors registered as beans in the context.
 invokeBeanFactoryPostProcessors(beanFactory);
 // Register bean processors that intercept bean creation.
 registerBeanPostProcessors(beanFactory);
 // Initialize message source for this context.
 initMessageSource();
 // Initialize event multicaster for this context.
 initApplicationEventMulticaster();
 // Initialize other special beans in specific context subclasses.
 onRefresh();
 // Check for listener beans and register them.
 registerListeners();
 // Instantiate all remaining (non-lazy-init) singletons.
 finishBeanFactoryInitialization(beanFactory);
 // Last step: publish corresponding event.
 finishRefresh();
 }
 catch (BeansException ex) {
 // Destroy already created singletons to avoid dangling resources.
 destroyBeans();
 // Reset 'active' flag.
 cancelRefresh(ex);
 }
 finally {
 // Reset common introspection caches in Spring's core, since we
 // might not ever need metadata for singleton beans anymore...
 resetCommonCaches();
 }
複製代碼

prepareRefresh():

     進行容器的預刷新工做。這步仍是比較簡單的。先是將容器置爲啓動狀態。以後調用initPropertySources(該方法爲空方法,提供給子類的覆蓋) 最後調用validateRequiredProperties來驗證是否包含一些必要參數(這裏必要參數依舊爲空)。

obtainFreshBeanFactory():

     對beanFactory進行刷新工做。先是調用refreshBeanFactory,使用CAS判斷工廠是否已經刷新(已刷新拋異常),以後給工廠bean一個序列化id, 並將工廠對象放入緩存(由序列化id映射)。最後返回工廠bean(調用容器無參構造函數建立的DefaultListableBeanFactory對象);

prepareBeanFactory(beanFactory):

進行beanFactory的準備工做:

  1. beanFactory添加類加載器,表達式解析器,屬性編輯器註冊器, ApplicationContextAwareProcessor
  2. 忽略某些類的自動注入(這些接口大多爲Spring爲實現類注入bean的功能接口,例如:ApplicationContextAware)。
  3. 指定BeanFactory,ResourceLoader,ApplicationEventPublisher,ApplicationContext這些類型自動注入時的類(除beanFactory爲當前beanFactory其他都爲當前容器)
  4. 爲工廠注入一些環境配置信息(beanName分別爲environment、systemProperties、systemEnvironment)

postProcessBeanFactory:

    該方法時BeanFactory初始化以後再進行後續的一些BeanFactory操做。對於AnnotationConfigApplicationContext這是父類的一個空方法。在SpringBoot建立的另外兩個web容器的時候(AnnotationConfigServletWebServerApplicationContextAnnotationConfigReactiveWebServerApplicationContext)會重寫該方法。之後可能會出個SpringBoot原理分析系列詳細會講到這兩個容器的建立及準備。

invokeBeanFactoryPostProcessors:

invokeBeanFactoryPostProcessors方法比較關鍵。該方法作了如下步驟:

  1. 執行ConfigurationClassPostProcessor,這個處理器主要來解析配置類(分爲完整配置類和精簡配置類,這裏只詳解帶@Configuration註解的完整配置類),主要用於註冊bean。
  2. 執行其餘BeanFactoryPostProcessor。(分爲BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor兩種接口)
執行ConfigurationClassPostProcessor:

該方法主要執行了步驟:

  1. ConfigurationClassParser的parse方法:
    1. 獲取@PropertySource註解信息(以後全部的獲取註解信息都是分析shouldSkip提到的searchWithGetSemantics方法完成的),使用processPropertySource解析添加配置文件信息。處理過程大體是先建立PropertySource(建立的時候調用loadProperties讀取配置文件信息)。以後將該配置文件信息添加到beanFactory的environmentbean對象中去。
    2. 獲取@ComponentScans註解信息(若未獲取到則爲配置類的目錄)。使用ComponentScanAnnocationParser來解析須要註冊的bean,以後調用ClassPathBeanDefinitionScanner的doScan來將beanDefinition註冊進容器。doScan作的事情就是掃包獲取指定包的全部class文件並篩選有@Component而且@Conditional匹配的class。BeanDefinition註冊過程就是以前提到的registerBeanDefinition方法。以後遍歷獲取到的BeanDefinitions執行parse。 操做將註冊進來的Bean裏的@PropertySource,@ComponentScans等註解的信息註冊進來(遞歸註冊)。
    3. @Import註解解析。processImports方法來執行該操做。將全部該註解引入的類註冊到容器當中。使用collectImports方法遞歸查找該類下全部的註解中包含的@Import引入的對象。以後即是遍歷處理操做:
      1. 若是引入對象是ImportSelector實現類,實例化該類。若是該類實現了Aware接口先給該類初始化這些屬性(包含BeanClassLoaderAware,BeanFactoryAware,EnvironmentAware,ResourceLoaderAware)。以後判斷若是該類實現類DeferredImportSelector接口就將其放入deferredImportSelectors後續處理。不然調用selectImports獲取import對象並執行processImports遞歸。
      2. 若是引入對象是ImportBeanDefinitionRegistrar實現類,和以前同樣先實例化再根據Aware初始化。最後將實例化後的類添加到帶有@Import類的ConfigurationClassimportBeanDefinitionRegistrars屬性中以便後續操做。
      3. 其餘狀況將其放入ConfigurationClassParserimportStackimports緩存(用於判斷該類是否須要解析)。生成該類的ConfigurationClass(帶有importedBy屬性)。
    4. @ImportResource和第一步相似這個引入的是spring的配置類。往帶有該註解的ConfigurationClassimportedResources屬性添加該
    5. retrieveBeanMethodMetadata,解析該類全部帶有@Bean的方法將其添加到該類的ConfigurationClass。
    6. processInterfaces,解析注入類中的全部接口中的default方法是否包含@Bean的,若是有就建立一個BeanMethod添加到該類的ConfigurationClass以便下一步來註冊該對象。這兩個方法查找了全部的@BeanMethod。
    7. 添加父類class到配置類中進行註冊操做,和以前的parse操做相同。
    8. 將當前解析類的ConfigurationClass放入ConfigurationClassParser的configurationClasses屬性中,爲以後解析作準備。
    9. processDeferredImportSelectors處理3中放入deferredImportSelectors緩存中的DeferredImportSelector。調用全部的selectors的selectImports方法來獲取全部導入類並封裝成SourceClass列表再去調用processImports來遞歸。(這麼多操做實際目的就是將全部的@Import生成ConfigurationClass或者放入importBeanDefinitionRegistrars爲以後loadBeanDefinitions作準備)
  2. ConfigurationClassBeanDefinitionReader的loadBeanDefinitions:
    1. 遍歷ConfigurationClass執行loadBeanDefinitionsForConfigurationClass。
    2. 判斷該ConfigurationClass是不是導入的(帶有importedBy屬性),若是是將給類註冊到beanFactory
    3. 解析該ConfigurationClass帶有@Bean的方法生成beanDefinition(該定義信息除了有Lazy等屬性外還有factoryBeanName和factoryMethodName)並註冊到容器當中。
    4. 從importedResources屬性中註冊beanDefinition。讀取配置文件信息獲取beanDefinition並註冊。
    5. 從1.3.2中放入importBeanDefinitionRegistrars屬性中調用ImportBeanDefinitionRegistrar的registerBeanDefinitions直接註冊到容器中。
執行BeanFactoryPostProcessor:

BeanFactoryPostProcessor排序執行:

  1. 獲取BeanDefinitionRegistryPostProcessor執行處理(postProcessBeanDefinitionRegistry)。以後執行回調(postProcessBeanFactory)
  2. 獲取BeanFactoryPostProcessor執行執行前置處理(postProcessBeanFactory)。以後執行後置處理(postProcessBeanFactory)
  3. 清除beanFactory緩存,清除mergedBeanDefinitions的未建立對象的定義信息。

registerBeanPostProcessors:

添加BeanPostProcessors:

  1. 添加BeanPostProcessorChecker處理器。
  2. 獲取全部的BeanPostProcessors排序並添加。 registerBeanPostProcessors過程很簡單就是將該處理器對象放入beanFactory,這個過程會經過getBean建立處理器對象。
  3. 添加ApplicationListenerDetector處理器。

執行順序:

  1. 實現PriorityOrdered接口。
  2. 實現Ordered接口。
  3. 沒有實現PriorityOrdered和Ordered接口的。
  4. 實現MergedBeanDefinitionPostProcessor接口的處理器。

initMessageSource:

國際化配置的信息。

initApplicationEventMulticaster:

初始化容器的事件廣播器。若是容器中沒有applicationEventMulticasterbean對象,建立一個SimpleApplicationEventMulticaster時間廣播器並註冊進beanFactory。

onRefresh:

能夠重寫的模板方法,以添加特定於上下文的刷新工做。對於AnnotationConfigApplicationContext這是個空方法。

registerListeners:

檢查監聽器bean並註冊它們:

  1. 註冊靜態指定的偵聽器。(添加到applicationListeners集合中)
  2. 從beanFactory獲取ApplicationListener類型的beanNames並註冊他們。
  3. 執行早期容器事件。

finishBeanFactoryInitialization:

將實例化的beanDefinition進行實例化:

  1. 若是容器中沒有字符串解析器,new字符串解析器(使用容器Environment中的解析器來解析,默認是PropertySourcesPropertyResolver)。
  2. 開啓容許緩存全部的beanDefinition而且將全部的beanDefinitions放入凍結配置狀況的緩存中。
  3. 使用beanFactory的preInstantiateSingletons來實例化全部的beanDefinition。
    1. 遍歷全部beanDefinition,獲取該bean組合的beanDefinition。若是該bean須要工廠建立的對象,先使用getBean獲取工廠對象再getBean獲取工產對象。不是工廠對象直接調用getBean。(getBean起到建立對象做用。建立對象時會調用BeanPostProcessor。詳細看這篇博客這篇博客)
    2. 遍歷全部的beanDefinition,getSingleton從緩存中獲取以前建立的Bean。若是該bean實現了SmartInitializingSingleton接口,執行接口方法afterSingletonsInstantiated。

finishRefresh:

  1. 清除上下文級資源緩存(這裏是資源reader對象)。
  2. 爲此上下文初始化生命週期處理器。(beanName:lifecycleProcessor),若是沒有獲取到默認註冊DefaultLifecycleProcessor。
  3. 調用生命週期處理器的onRefresh:
    1. 獲取beanFactory中全部實現Lifecycle接口的beanName,遍歷,篩選出實現Lifecycle接口的必須在以前被實例化了或者實現SmartLifecycle接口。(過濾lifecycleProcessor)
    2. 遍歷1獲取的全部Lifecycle中實現SmartLifecycle接口而且該類的isAutoStartup方法爲true的對象。
    3. 遍歷2中獲取的Lifecycle執行start方法。
  4. 添加ContextRefreshedEvent的
  5. 向LiveBeansView中註冊該容器。(JMX的相關操做)

總結:

以上就是AnnotationConfigApplicationContext的建立過程。這裏解析的都是基於註解的解析方式,由興趣的小夥伴還能夠看下基於xml的解析(應該只有Resource讀取有所差別),以後我會本身實現一個能夠擴展的簡單容器(項目名字已經起好了叫seed😁),應該還會整合這個容器和netty(還在學習中...)實現一個異步的Controller層的框架,但願個人文章能幫到你們。

相關文章
相關標籤/搜索