java複習筆記3--SpringCloud系列一:微服務啟動原理探索之beanFactory載入
昨天,我們對SpringApplication的初始化以及SpringApplication.run方法中的部分程式碼進行了解讀和追蹤。這一塊的重點就是Spring的 SPI,META-INF/spring.factories檔案的格式以及載入機制。一定要花時間去研讀這塊的程式碼,spring的初始化基本都會用這個方法去注入,其次就是java.awt.headless模式以及用途,其他的屬性注入就不做過多解釋了。 今天,主要是將剩下的流程走完,尤其是昨天提到的,refreshContext這個方法,涉及東西較多,今天會重點研讀這個。 首先,refreshContext方法主要是呼叫AbstractApplicationContext的refresh方法,先上一段原始碼:
public void refresh() throws BeansException, IllegalStateException { Object var1 = this.startupShutdownMonitor; synchronized(this.startupShutdownMonitor) { this.prepareRefresh(); ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory); try { this.postProcessBeanFactory(beanFactory); this.invokeBeanFactoryPostProcessors(beanFactory); this.registerBeanPostProcessors(beanFactory); this.initMessageSource(); this.initApplicationEventMulticaster(); this.onRefresh(); this.registerListeners(); this.finishBeanFactoryInitialization(beanFactory); this.finishRefresh(); } catch (BeansException var9) { if(this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9); } this.destroyBeans(); this.cancelRefresh(var9); throw var9; } finally { this.resetCommonCaches(); } } }
同步鎖
第一眼就能看見整個synchronized關鍵字,說明方法是同步加鎖的,為了防止重複注入屬性或者例項化,這裡使用的是moniter物件。而沒有直接在方法上加鎖,也是為了和其他方法進行同步加鎖,比如後面的close方法和destroy以及registerShutdownHook。針對於鎖和執行緒安全,之後會花大量時間去溫習。
設定此次重新整理applicationContext上下文的狀態
prepareRefresh主要就是設定上下文重新整理狀態
初始化beanFactory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); this.prepareBeanFactory(beanFactory);
這兩行程式碼主要是對ApplicationContex中的beanFactory進行例項化和屬性賦值。將ApplicationContex中的屬性賦值給beanFactory容器中,比如classLoader,裝配規則,bean的後置載入器。其實就是解析注入bean所需要的一些依賴。
bean的裝配
invokeBeanFactoryPostProcessors這個步驟是整個最核心的部分,也是最繁瑣的部分。我們先貼一下原始碼:
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet();
ArrayList regularPostProcessors;
ArrayList registryProcessors;
int var9;
ArrayList currentRegistryProcessors;
String[] postProcessorNames;
if(beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry)beanFactory;
regularPostProcessors = new ArrayList();
registryProcessors = new ArrayList();
Iterator var6 = beanFactoryPostProcessors.iterator();
while(var6.hasNext()) {
BeanFactoryPostProcessor postProcessor = (BeanFactoryPostProcessor)var6.next();
if(postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor = (BeanDefinitionRegistryPostProcessor)postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
} else {
regularPostProcessors.add(postProcessor);
}
}
currentRegistryProcessors = new ArrayList();
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
String[] var16 = postProcessorNames;
var9 = postProcessorNames.length;
int var10;
String ppName;
for(var10 = 0; var10 < var9; ++var10) {
ppName = var16[var10];
if(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
var16 = postProcessorNames;
var9 = postProcessorNames.length;
for(var10 = 0; var10 < var9; ++var10) {
ppName = var16[var10];
if(!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
boolean reiterate = true;
while(reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
String[] var19 = postProcessorNames;
var10 = postProcessorNames.length;
for(int var26 = 0; var26 < var10; ++var26) {
String ppName = var19[var26];
if(!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
invokeBeanFactoryPostProcessors((Collection)registryProcessors, (ConfigurableListableBeanFactory)beanFactory);
invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
} else {
invokeBeanFactoryPostProcessors((Collection)beanFactoryPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
}
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
regularPostProcessors = new ArrayList();
registryProcessors = new ArrayList();
currentRegistryProcessors = new ArrayList();
postProcessorNames = postProcessorNames;
int var20 = postProcessorNames.length;
String ppName;
for(var9 = 0; var9 < var20; ++var9) {
ppName = postProcessorNames[var9];
if(!processedBeans.contains(ppName)) {
if(beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
regularPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
} else if(beanFactory.isTypeMatch(ppName, Ordered.class)) {
registryProcessors.add(ppName);
} else {
currentRegistryProcessors.add(ppName);
}
}
}
sortPostProcessors(regularPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors((Collection)regularPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList();
Iterator var21 = registryProcessors.iterator();
while(var21.hasNext()) {
String postProcessorName = (String)var21.next();
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors((Collection)orderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList();
Iterator var24 = currentRegistryProcessors.iterator();
while(var24.hasNext()) {
ppName = (String)var24.next();
nonOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors((Collection)nonOrderedPostProcessors, (ConfigurableListableBeanFactory)beanFactory);
beanFactory.clearMetadataCache();
}
昨天,說到了,prepareContext這個方法初始化context的容器的時候,注入了三個beanFactoryPostProcessor。BeanFactoryPostProcessor在容器例項化任何bean之前讀取bean的定義(配置元資料),並可以修改它。同時可以定義多個BeanFactoryPostProcessor,通過設定getOrder返回值來確定各個BeanFactoryPostProcessor執行順序。這樣spring有很好的拓展性
回到上面的程式碼,成員變數就是用來防止重複注入或者重複呼叫BeanFactoryPostProcessor的,然後, if(beanFactory instanceof BeanDefinitionRegistry) 這裡就是判斷beanFactory 是否繼承於BeanDefinitionRegistry的,如果是,就遍歷之前注入到context中的所有的BeanFactoryPostProcessor。呼叫他們的postProcessBeanDefinitionRegistry這個方法。 遍歷完成之後,currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));這個方法就是注入了ConfigurationClassPostProcessor,這個方法是掃描並建立bean,例項化到Spring上下文容器中最重要的一個類。
bean的解析過程 parser
//注入ConfigurationClassPostProcessor
registryProcessors.addAll(currentRegistryProcessors);
//啟用,即呼叫ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
ConfigurationClassPostProcessor中的postProcessBeanDefinitionRegistry方法是解析和裝配bean的核心,先上一下原始碼:
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList();
// 1. 獲取已經註冊的bean名稱
String[] candidateNames = registry.getBeanDefinitionNames();
String[] var4 = candidateNames;
int var5 = candidateNames.length;
for(int var6 = 0; var6 < var5; ++var6) {
String beanName = var4[var6];
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if(!ConfigurationClassUtils.isFullConfigurationClass(beanDef) && !ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if(ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 1.1. 判斷對應bean是否為配置類,如果是,則加入到configCandidates
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
} else if(this.logger.isDebugEnabled()) {
// 1.2. 如果BeanDefinition 中的configurationClass 屬性為full 或者lite ,則意味著已經處理過了,直接跳過
this.logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 1.3 如果存在配置類,進行排序
if(!configCandidates.isEmpty()) {
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
SingletonBeanRegistry sbr = null;
if(registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry)registry;
if(!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator)sbr.getSingleton("org.springframework.context.annotation.internalConfigurationBeanNameGenerator");
if(generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if(this.environment == null) {
this.environment = new StandardEnvironment();
}
//1.4. 例項化ConfigurationClassParser 為了解析 各個配置類
ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment, this.resourceLoader, this.componentScanBeanNameGenerator, registry);
//1.5 去重
Set<BeanDefinitionHolder> candidates = new LinkedHashSet(configCandidates);
HashSet alreadyParsed = new HashSet(configCandidates.size());
do {
//1.6進行解析呼叫的方法
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
if(this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment, this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if(registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet();
Iterator var12 = alreadyParsed.iterator();
while(var12.hasNext()) {
ConfigurationClass configurationClass = (ConfigurationClass)var12.next();
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
String[] var23 = newCandidateNames;
int var24 = newCandidateNames.length;
for(int var14 = 0; var14 < var24; ++var14) {
String candidateName = var23[var14];
if(!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if(ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) && !alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
} while(!candidates.isEmpty());
if(sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if(this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory)this.metadataReaderFactory).clearCache();
}
}
}
先大致分析,瞭解一下這個方法的思路。首先,遍歷所有的已經註冊的bean名稱,判斷對應bean是否為配置檔案bean(包含Configuration註解),加入configCandidates中後,然後對他們按照order進行排序。然後例項化ConfigurationClassParser 為了解析各個配置類.例項化2個set,candidates 用於將之前加入的configCandidates 進行去重,alreadyParsed 用於判斷是否處理過。再呼叫ConfigurationClassParser#parse進行解析。而進去發現最終呼叫的是ConfigurationClassParser#processConfigurationClass
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if(!this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
ConfigurationClass existingClass = (ConfigurationClass)this.configurationClasses.get(configClass);
if(existingClass != null) {
if(configClass.isImported()) {
if(existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
return;
}
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
ConfigurationClassParser.SourceClass sourceClass = this.asSourceClass(configClass);
do {
sourceClass = this.doProcessConfigurationClass(configClass, sourceClass);
} while(sourceClass != null);
this.configurationClasses.put(configClass, configClass);
}
}
首先判斷該bean是否被跳過,然後對Class進行包裝,呼叫sourceClass = doProcessConfigurationClass(configClass,sourceClass)處理Application類。
@Nullable
protected final ConfigurationClassParser.SourceClass doProcessConfigurationClass(ConfigurationClass configClass, ConfigurationClassParser.SourceClass sourceClass) throws IOException {
this.processMemberClasses(configClass, sourceClass);
Iterator var3 = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class, PropertySource.class).iterator();
AnnotationAttributes importResource;
while(var3.hasNext()) {
importResource = (AnnotationAttributes)var3.next();
if(this.environment instanceof ConfigurableEnvironment) {
this.processPropertySource(importResource);
} else {
this.logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() + "]. Reason: Environment must implement ConfigurableEnvironment");
}
}
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if(!componentScans.isEmpty() && !this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
Iterator var13 = componentScans.iterator();
while(var13.hasNext()) {
AnnotationAttributes componentScan = (AnnotationAttributes)var13.next();
Set<BeanDefinitionHolder> scannedBeanDefinitions = this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
Iterator var7 = scannedBeanDefinitions.iterator();
while(var7.hasNext()) {
BeanDefinitionHolder holder = (BeanDefinitionHolder)var7.next();
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if(bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if(ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
this.parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
this.processImports(configClass, sourceClass, this.getImports(sourceClass), true);
importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if(importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
String[] var19 = resources;
int var21 = resources.length;
for(int var22 = 0; var22 < var21; ++var22) {
String resource = var19[var22];
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
Set<MethodMetadata> beanMethods = this.retrieveBeanMethodMetadata(sourceClass);
Iterator var17 = beanMethods.iterator();
while(var17.hasNext()) {
MethodMetadata methodMetadata = (MethodMetadata)var17.next();
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
this.processInterfaces(configClass, sourceClass);
if(sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if(superclass != null && !superclass.startsWith("java") && !this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
return sourceClass.getSuperClass();
}
}
return null;
}
核心方法就是this.processPropertySource(importResource);
private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
String name = propertySource.getString("name");
if(!StringUtils.hasLength(name)) {
name = null;
}
String encoding = propertySource.getString("encoding");
if(!StringUtils.hasLength(encoding)) {
encoding = null;
}
String[] locations = propertySource.getStringArray("value");
Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");
Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
PropertySourceFactory factory = factoryClass == PropertySourceFactory.class?DEFAULT_PROPERTY_SOURCE_FACTORY:(PropertySourceFactory)BeanUtils.instantiateClass(factoryClass);
String[] var8 = locations;
int var9 = locations.length;
for(int var10 = 0; var10 < var9; ++var10) {
String location = var8[var10];
try {
String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
Resource resource = this.resourceLoader.getResource(resolvedLocation);
this.addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
} catch (FileNotFoundException | UnknownHostException | IllegalArgumentException var14) {
if(!ignoreResourceNotFound) {
throw var14;
}
if(this.logger.isInfoEnabled()) {
this.logger.info("Properties location [" + location + "] not resolvable: " + var14.getMessage());
}
}
}
}
通過註解中的資訊獲取資源資訊,然後新增到MutablePropertySourcespropertySources = ((ConfigurableEnvironment)this.environment).getPropertySources()中。之後就是解析掃描ComponentScan。Set componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);之後,就是獲取資源路徑,在獲取到path路徑以後spring採用類載入器獲取指定Class檔案對應的資源資訊,根據不同的元資料,進行不同的解析。 至此,整個流程基本結束了,由於東西較多,自己看著也比較迷糊,先大致過一遍,應該漏了許多細節,大家可以提出來一起討論,之後對於這塊,會繼續花時間走讀程式碼,再做一個詳細的說明,並會結合自己的程式碼去說明流程了專案中應用。