這篇博客是對Spring(5.0.7)的ioc容器建立過程的解析,也是博主不斷debug幾天的成果。內容可能有點多,講的也可能比較枯燥。不過我相信個人分析對你們理解spring容器的整個工做原理仍是有一些幫助的。php
先是調用它的無參構造函數,初始化一些信息。
無參構造函數中new
了AnnotatedBeanDefinitionReader
和ClassPathBeanDefiitionScanner
賦值給reader
context的scanner
屬性。java
new
AnnotatedBeanDefinitionReader對象: 將該容器對象做爲BeanDefinitionRegistry
賦值給registry
屬性,而且new
了一個ConditionEvaluator
賦值給conditionEvaluator
屬性。以後調用registerAnnotationConfigProcessors
方法將全部的annotation處理器註冊進容器。web
這是spring對該類的描述Internal class used to evaluate {@link Conditional} annotations.
。能夠看出這個類是@Conditional
註解的一個解析器。在建立該類的時候利用deduceBeanFactory
給該對象初始化了一個DefaultListableBeanFactory
,而且該類是從容器中獲取的。spring
該方法先是給容器的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
new
ClassPathBeanDefinitionScanner對象:先是調用這個構造方法:app
registerDefaultFilters
,
setEnvironment
,
setResourceLoader
從名字咱們不難看出這是建立默認過濾器的方法;
其實是往該對象中添加了一個匹配@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));
}
複製代碼
同樣看名字咱們就能知道這是設置環境信息的。就是將以前建立AnnotatedBeanDefinitionReader
對象時獲取的StandardEnvironment
設置給該對象的environment
屬性。異步
該方法分別給該對象的resourcePatternResolver
,metadataReaderFactory
,componentsIndex
屬性初始化。resourcePatternResolver
對象其實就是容器對象.... metadataReaderFactory
是一個從容器resourceCaches
屬性拷貝過來的ConcurrentHashMap
。resourcePatternResolver
多是在加載META-INF/spring.components
這個配置文件吧。具體我也不太清楚。
至此spring容器的無參構造函數終於時調用完成了(😓)這只是簡單的一步並且不少地方即便是知道了它在幹什麼仍是不清楚他爲何這麼作若是有更瞭解的大佬還望指教編輯器
將Config類註冊進來,其實就是調用以前建立的AnnotatedBeanDefinitionReader
對象的register
方法將咱們所傳入的配置類註冊到容器當中。咱們能夠直接看AnnotatedBeanDefinitionReader
對象的doRegisterBean
方法:
該方法先是建立了Config對象的定義信息AnnotatedGenericBeanDefinition
。以後調用如下方法shouldSkip
,resolveScopeMetadata
,generateBeanName
,processCommonDefinitionAnnotations
,applyScopedProxyMode
,registerBeanDefinition
該方法先經過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);
}
}
}
}
複製代碼
獲取該bean的scope(這裏就不細講spring bean的做用域了不懂的自行百度),ScopeMetadata對象的值默認爲singleton
,因此若是該類沒有@Scope
註解默認爲單例的。
獲取該bean的@Component
註解標註的beanName,若是沒有默認爲類sortName。 獲取類上的@Component
註解步驟與第一步時獲取@Conditional
註解相似(遞歸獲取註解-排除java註解)這裏就不細講了。
對@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"));
}
}
複製代碼
判斷是否須要建立代理對象。若是須要調用ScopedProxyCreator.createScopedProxy
方法建立。(待補全代理對象的建立過程...)
從方法名能夠看出這部是真正的註冊beanDefinition。真正調用的是容器中的BeanFactory(這裏是DefaultListableBeanFactory
)的registerBeanDefinition
方法。首先驗證beanDefinition的信息(具體我也沒看懂在幹什麼)。以後判斷該beanDefinition是否被註冊過(若註冊過符合條件覆蓋以前的beanDefinition)。以後就是第一次註冊該bean的操做(和調用無參構造函數註冊過程一致詳情。)
register
方法分析到這裏就結束了,其實作的事情就是將配置類註冊到容器當中。
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();
}
複製代碼
進行容器的預刷新工做。這步仍是比較簡單的。先是將容器置爲啓動狀態。以後調用initPropertySources
(該方法爲空方法,提供給子類的覆蓋) 最後調用validateRequiredProperties
來驗證是否包含一些必要參數(這裏必要參數依舊爲空)。
對beanFactory
進行刷新工做。先是調用refreshBeanFactory
,使用CAS判斷工廠是否已經刷新(已刷新拋異常),以後給工廠bean一個序列化id, 並將工廠對象放入緩存(由序列化id映射)。最後返回工廠bean(調用容器無參構造函數建立的DefaultListableBeanFactory
對象);
進行beanFactory
的準備工做:
beanFactory
添加類加載器,表達式解析器,屬性編輯器註冊器, ApplicationContextAwareProcessor
。BeanFactory
,ResourceLoader
,ApplicationEventPublisher
,ApplicationContext
這些類型自動注入時的類(除beanFactory
爲當前beanFactory
其他都爲當前容器) 該方法時BeanFactory初始化以後再進行後續的一些BeanFactory操做。對於AnnotationConfigApplicationContext
這是父類的一個空方法。在SpringBoot建立的另外兩個web容器的時候(AnnotationConfigServletWebServerApplicationContext
、AnnotationConfigReactiveWebServerApplicationContext
)會重寫該方法。之後可能會出個SpringBoot原理分析系列詳細會講到這兩個容器的建立及準備。
invokeBeanFactoryPostProcessors
方法比較關鍵。該方法作了如下步驟:
@Configuration
註解的完整配置類),主要用於註冊bean。該方法主要執行了步驟:
ConfigurationClassParser
的parse方法:
@PropertySource
註解信息(以後全部的獲取註解信息都是分析shouldSkip
提到的searchWithGetSemantics方法完成的),使用processPropertySource解析添加配置文件信息。處理過程大體是先建立PropertySource(建立的時候調用loadProperties讀取配置文件信息)。以後將該配置文件信息添加到beanFactory的environment
bean對象中去。@ComponentScans
註解信息(若未獲取到則爲配置類的目錄)。使用ComponentScanAnnocationParser
來解析須要註冊的bean,以後調用ClassPathBeanDefinitionScanner
的doScan來將beanDefinition註冊進容器。doScan作的事情就是掃包獲取指定包的全部class文件並篩選有@Component
而且@Conditional
匹配的class。BeanDefinition註冊過程就是以前提到的registerBeanDefinition方法。以後遍歷獲取到的BeanDefinitions執行parse。 操做將註冊進來的Bean裏的@PropertySource
,@ComponentScans
等註解的信息註冊進來(遞歸註冊)。@Import
註解解析。processImports方法來執行該操做。將全部該註解引入的類註冊到容器當中。使用collectImports方法遞歸查找該類下全部的註解中包含的@Import
引入的對象。以後即是遍歷處理操做:
ImportSelector
實現類,實例化該類。若是該類實現了Aware
接口先給該類初始化這些屬性(包含BeanClassLoaderAware
,BeanFactoryAware
,EnvironmentAware
,ResourceLoaderAware
)。以後判斷若是該類實現類DeferredImportSelector接口就將其放入deferredImportSelectors
後續處理。不然調用selectImports獲取import對象並執行processImports遞歸。ImportBeanDefinitionRegistrar
實現類,和以前同樣先實例化再根據Aware
初始化。最後將實例化後的類添加到帶有@Import
類的ConfigurationClass
的importBeanDefinitionRegistrars
屬性中以便後續操做。ConfigurationClassParser
的importStack
的imports
緩存(用於判斷該類是否須要解析)。生成該類的ConfigurationClass
(帶有importedBy
屬性)。@ImportResource
和第一步相似這個引入的是spring的配置類。往帶有該註解的ConfigurationClass
的importedResources
屬性添加該retrieveBeanMethodMetadata
,解析該類全部帶有@Bean
的方法將其添加到該類的ConfigurationClass。processInterfaces
,解析注入類中的全部接口中的default方法是否包含@Bean
的,若是有就建立一個BeanMethod添加到該類的ConfigurationClass以便下一步來註冊該對象。這兩個方法查找了全部的@Bean
Method。ConfigurationClass
放入ConfigurationClassParser
的configurationClasses屬性中,爲以後解析作準備。processDeferredImportSelectors
處理3中放入deferredImportSelectors
緩存中的DeferredImportSelector。調用全部的selectors的selectImports方法來獲取全部導入類並封裝成SourceClass
列表再去調用processImports來遞歸。(這麼多操做實際目的就是將全部的@Import生成ConfigurationClass
或者放入importBeanDefinitionRegistrars
爲以後loadBeanDefinitions作準備)ConfigurationClassBeanDefinitionReader
的loadBeanDefinitions:
ConfigurationClass
執行loadBeanDefinitionsForConfigurationClass。ConfigurationClass
是不是導入的(帶有importedBy
屬性),若是是將給類註冊到beanFactoryConfigurationClass
帶有@Bean
的方法生成beanDefinition(該定義信息除了有Lazy等屬性外還有factoryBeanName和factoryMethodName)並註冊到容器當中。importBeanDefinitionRegistrars
屬性中調用ImportBeanDefinitionRegistrar的registerBeanDefinitions直接註冊到容器中。BeanFactoryPostProcessor排序執行:
mergedBeanDefinitions
的未建立對象的定義信息。添加BeanPostProcessors:
getBean
建立處理器對象。執行順序:
國際化配置的信息。
初始化容器的事件廣播器。若是容器中沒有applicationEventMulticaster
bean對象,建立一個SimpleApplicationEventMulticaster時間廣播器並註冊進beanFactory。
能夠重寫的模板方法,以添加特定於上下文的刷新工做。對於AnnotationConfigApplicationContext這是個空方法。
檢查監聽器bean並註冊它們:
將實例化的beanDefinition進行實例化:
preInstantiateSingletons
來實例化全部的beanDefinition。
以上就是AnnotationConfigApplicationContext的建立過程。這裏解析的都是基於註解的解析方式,由興趣的小夥伴還能夠看下基於xml的解析(應該只有Resource讀取有所差別),以後我會本身實現一個能夠擴展的簡單容器(項目名字已經起好了叫seed😁),應該還會整合這個容器和netty(還在學習中...)實現一個異步的Controller層的框架,但願個人文章能幫到你們。