国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁(yè) > news >正文

渭南公司做網(wǎng)站蘇州seo關(guān)鍵詞優(yōu)化價(jià)格

渭南公司做網(wǎng)站,蘇州seo關(guān)鍵詞優(yōu)化價(jià)格,怎么做鏈接有圖和文字,嘉定個(gè)人網(wǎng)站建設(shè)tips: ConfigurationClassParser 是 Springframework 中的重要類(lèi)。 本章主要是源碼理解,有難度和深度,也枯燥乏味,可以根據(jù)實(shí)際情況選擇閱讀。 位置:org.springframework.context.annotation.ConfigurationClassPars…

tips: ConfigurationClassParser 是 Springframework 中的重要類(lèi)。

本章主要是源碼理解,有難度和深度,也枯燥乏味,可以根據(jù)實(shí)際情況選擇閱讀。

位置:org.springframework.context.annotation.ConfigurationClassParser

ConfigurationClassParser 它是解密 configuration 的關(guān)鍵。理解 ConfigurationClassParser 對(duì)理解整個(gè) Spring 框架至關(guān)重要。

一、作用是什么

ConfigurationClassParser是一個(gè)非常重要的類(lèi),它主要用于解析帶有@Configuration注解的類(lèi)。

@Configuration注解表明該類(lèi)用作配置類(lèi),其中可以定義bean和Spring容器應(yīng)如何初始化和管理這些bean。

ConfigurationClassParser的作用可以從以下幾個(gè)方面詳細(xì)闡述:

  1. 解析導(dǎo)入的配置@Import注解允許一個(gè)配置類(lèi)導(dǎo)入另一個(gè)配置類(lèi)。ConfigurationClassParser解析這些@Import注解,確保所有導(dǎo)入的配置也被處理和應(yīng)用。
  2. 處理屬性注入:通過(guò)@PropertySource注解,可以指定一些屬性文件,這些屬性文件中的屬性可以被注入到Spring管理的bean中。ConfigurationClassParser負(fù)責(zé)解析這些注解,并確保屬性文件被加載且其值可用于注入。
  3. 處理@Conditional注解: Spring框架允許在bean的注冊(cè)過(guò)程中使用條件邏輯,@Conditional注解及其派生注解(例如@ConditionalOnClass@ConditionalOnProperty等)使得只有在滿足特定條件時(shí),才會(huì)進(jìn)行bean的注冊(cè)。ConfigurationClassParser負(fù)責(zé)解析這些條件注解并應(yīng)用其邏輯。
  4. processDeferredImportSelectors#processImports 處理擴(kuò)展配置( Starter 能夠被處理的核心分支)

二、觸發(fā)時(shí)機(jī)

SpringBoot 應(yīng)用啟動(dòng)過(guò)程中,通過(guò)后置處理器去觸發(fā) ConfigurationClassPostProcessor。 然后再調(diào)用 ConfigurationClassParser類(lèi)解析

public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {....
}

處理如下:

下面我們將詳細(xì)分析源碼流程。

三、ConfigurationClassPostProcessor

下面是 ConfigurationClassPostProcessor 部分核心代碼。

入口方法 processConfigBeanDefinitions(BeanDefinitionRegistry registry) 。開(kāi)始分析這段代碼。

注意這里有一個(gè) do...while

	do {.....}while (!candidates.isEmpty());

它將逐一識(shí)別和解析配置類(lèi),然后將配置類(lèi)中定義的Bean注冊(cè)到Spring容器中。這個(gè)過(guò)程通過(guò)不斷循環(huán)直到?jīng)]有新的配置類(lèi)候選者出現(xiàn)為止,確保了所有相關(guān)的配置都被完整地處理。

// 創(chuàng)建一個(gè)配置類(lèi)解析器,用于解析和處理配置類(lèi)信息
ConfigurationClassParser parser = new ConfigurationClassParser(this.metadataReaderFactory, this.problemReporter, this.environment,this.resourceLoader, this.componentScanBeanNameGenerator, registry);// 初始化一個(gè)集合,用于存儲(chǔ)待處理的配置類(lèi)候選者
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 初始化一個(gè)集合,用于跟蹤已經(jīng)解析過(guò)的配置類(lèi),以避免重復(fù)解析
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());// 循環(huán)處理,直到?jīng)]有新的配置類(lèi)候選者
do {// 解析當(dāng)前候選者中的配置類(lèi)parser.parse(candidates);// 對(duì)解析結(jié)果進(jìn)行驗(yàn)證parser.validate();// 從解析器中獲取已解析的配置類(lèi)集合Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());// 移除已經(jīng)處理過(guò)的,避免重復(fù)處理configClasses.removeAll(alreadyParsed);// 如果讀取器未初始化,創(chuàng)建一個(gè)配置類(lèi)Bean定義讀取器if (this.reader == null) {this.reader = new ConfigurationClassBeanDefinitionReader(registry, this.sourceExtractor, this.resourceLoader, this.environment,this.importBeanNameGenerator, parser.getImportRegistry());}// 加載并注冊(cè)配置類(lèi)中定義的Beanthis.reader.loadBeanDefinitions(configClasses);// 將這批配置類(lèi)標(biāo)記為“已解析”alreadyParsed.addAll(configClasses);// 清空候選者集合,為下一輪尋找新候選者做準(zhǔn)備candidates.clear();// 檢查是否有新的Bean定義被注冊(cè)(可能由@Configuration類(lèi)引入)if (registry.getBeanDefinitionCount() > candidateNames.length) {// 重新獲取所有Bean定義的名稱(chēng)String[] newCandidateNames = registry.getBeanDefinitionNames();// 創(chuàng)建一個(gè)舊候選名稱(chēng)的集合,用于辨識(shí)新的候選者Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));// 創(chuàng)建一個(gè)集合,用于跟蹤已經(jīng)解析的配置類(lèi)的類(lèi)名Set<String> alreadyParsedClasses = new HashSet<>();for (ConfigurationClass configurationClass : alreadyParsed) {alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());}// 遍歷新的Bean定義名稱(chēng),尋找新的配置類(lèi)候選者for (String candidateName : newCandidateNames) {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));}}}// 更新候選名稱(chēng)列表,以反映新的Bean定義candidateNames = newCandidateNames;}
// 如果還有未處理的候選者,繼續(xù)循環(huán)
} while (!candidates.isEmpty());

特別說(shuō)明,對(duì)于 Bean 的加載和實(shí)例化不在本范圍了,不進(jìn)行講解。感興趣可以閱讀相關(guān)章節(jié)。

上面的這段代碼是 ConfigurationClassPostProcessor 核心。解析來(lái)的重頭戲。ConfigurationClassParser

四、ConfigurationClassParser

從這行代碼開(kāi)始入手parser.parse(candidates);

  1. parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
  2. processDeferredImportSelectors(); // 處理前面推遲的ImportSelector,一些二方包的導(dǎo)入類(lèi),將在這個(gè)方法中實(shí)現(xiàn)。 例如,我們配置在 Starter Spring.factories 中的自動(dòng)導(dǎo)入類(lèi),將在這一環(huán)境被加載
parse方法入口
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {// 如果這個(gè)配置類(lèi)應(yīng)該根據(jù)條件注解被跳過(guò),則直接返回不進(jìn)行處理if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {return;}// 嘗試從已處理的配置類(lèi)映射中獲取這個(gè)配置類(lèi)ConfigurationClass existingClass = this.configurationClasses.get(configClass);// 如果找到了已存在的配置類(lèi)if (existingClass != null) {// 如果當(dāng)前處理的是一個(gè)導(dǎo)入的配置類(lèi)if (configClass.isImported()) {// 如果已存在的配置類(lèi)也是導(dǎo)入的,則合并導(dǎo)入來(lái)源if (existingClass.isImported()) {existingClass.mergeImportedBy(configClass);}// 如果已存在的配置類(lèi)不是導(dǎo)入的,則忽略當(dāng)前導(dǎo)入的配置類(lèi),保留現(xiàn)有的非導(dǎo)入類(lèi)return;}else {// 如果找到顯式的bean定義,可能是意在替換一個(gè)導(dǎo)入的類(lèi)。// 移除舊的配置類(lèi),采用新的配置類(lèi)。this.configurationClasses.remove(configClass);this.knownSuperclasses.values().removeIf(configClass::equals);}}// 遞歸處理配置類(lèi)及其超類(lèi)層次結(jié)構(gòu)SourceClass sourceClass = asSourceClass(configClass);do {// 處理當(dāng)前配置類(lèi)并更新sourceClass為配置類(lèi)的超類(lèi),準(zhǔn)備下一輪處理sourceClass = doProcessConfigurationClass(configClass, sourceClass);} while (sourceClass != null); // 如果sourceClass為null,表示超類(lèi)已經(jīng)處理完畢// 將處理完的配置類(lèi)放入配置類(lèi)映射中,標(biāo)記為已處理this.configurationClasses.put(configClass, configClass);
}

上面可以理解,解析 MyApplication 類(lèi)所在工程中的類(lèi)。最終的解析由 doProcessConfigurationClass 實(shí)現(xiàn)

processDeferredImportSelectors

負(fù)責(zé)處理那些被延遲的特殊接口,使用它來(lái)按需動(dòng)態(tài)地導(dǎo)入配置。

這些常常依賴于某些條件才被執(zhí)行,所以被延遲處理。

// 定義處理延遲的ImportSelector的方法
private void processDeferredImportSelectors() {// 獲取之前收集的所有延遲處理的ImportSelectorList<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;// 將引用置為null,表示開(kāi)始處理過(guò)程,防止重復(fù)處理this.deferredImportSelectors = null;// 如果沒(méi)有需要處理的延遲ImportSelector,則直接返回if (deferredImports == null) {return;}...... // 遍歷所有的延遲ImportSelectorfor (DeferredImportSelectorHolder deferredImport : deferredImports) {// 獲取與當(dāng)前ImportSelector相關(guān)聯(lián)的配置類(lèi)ConfigurationClass configClass = deferredImport.getConfigurationClass();try {// 調(diào)用ImportSelector的selectImports方法,獲取所有的導(dǎo)入類(lèi)名String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());// 處理這些導(dǎo)入的類(lèi),將它們作為配置類(lèi)進(jìn)行進(jìn)一步的處理processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);}}
}

這個(gè)方法的主要作用將是找出符合條件的 imports 類(lèi)。最終還是由processImports() 處理。

到這里,spring.factories 符合條件的一些類(lèi)將被加載。核心代碼deferredImport.getImportSelector().selectImports(configClass.getMetadata());

到這里我們基本上了解了 Starter 是如何被引入進(jìn)來(lái)的。

真正解析的方法 doProcessConfigurationClass

doProcessConfigurationClass

它遞歸地處理嵌套類(lèi)、處理@PropertySource注解、處理@ComponentScan注解、處理@Import注解、處理@ImportResource注解、處理@Bean方法、處理接口上的默認(rèn)方法,最后處理父類(lèi)

  1. 處理成員類(lèi):方法首先遞歸地處理配置類(lèi)中定義的任何成員類(lèi)(嵌套類(lèi))。
  2. 處理@PropertySource注解:然后遍歷配置類(lèi)上的所有@PropertySource注解,這些注解用來(lái)指明屬性文件的位置。如果當(dāng)前的環(huán)境實(shí)現(xiàn)了ConfigurableEnvironment接口,則處理注解指定的屬性源
  3. 處理@ComponentScan注解:接下來(lái),處理配置類(lèi)上的所有@ComponentScan注解,這些注解指示Spring掃描特定包下的組件(即帶有@Component@Service等注解的類(lèi)),并注冊(cè)為Spring容器中的Bean。如果有條件注解指示在此階段跳過(guò)處理,則不執(zhí)行掃描。
  4. 處理@Import注解:處理配置類(lèi)上的@Import注解,這些注解用來(lái)導(dǎo)入其他配置類(lèi)或配置選擇器,允許模塊化地組織配置。
  5. 處理@ImportResource注解:處理配置類(lèi)上的@ImportResource注解,這些注解用于導(dǎo)入XML配置文件。
  6. 處理@Bean方法:收集配置類(lèi)中所有帶有@Bean注解的方法的元數(shù)據(jù),并將它們添加到配置類(lèi)對(duì)象中。這些方法定義了應(yīng)該由Spring容器管理的Bean。
  7. 處理接口上的默認(rèn)方法:如果配置類(lèi)實(shí)現(xiàn)了接口,并在這些接口上定義了默認(rèn)方法,這些方法也會(huì)被處理。
  8. 處理父類(lèi):最后,如果配置類(lèi)有超類(lèi),那么這個(gè)方法會(huì)檢查超類(lèi)是否也是一個(gè)配置類(lèi),不是Java內(nèi)置類(lèi),并且還沒(méi)有被處理過(guò)。如果滿足條件,則遞歸地處理這個(gè)超類(lèi)。

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)throws IOException {// 首先,遞歸處理任何成員類(lèi)(嵌套類(lèi))processMemberClasses(configClass, sourceClass);// 處理所有的@PropertySource注解for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {// 如果環(huán)境實(shí)現(xiàn)了ConfigurableEnvironment接口if (this.environment instanceof ConfigurableEnvironment) {// 處理@PropertySource注解processPropertySource(propertySource);} else {// 如果環(huán)境沒(méi)有實(shí)現(xiàn)ConfigurableEnvironment接口logger.warn("忽略了[" + sourceClass.getMetadata().getClassName() +"]上的@PropertySource注解。原因:環(huán)境必須實(shí)現(xiàn)ConfigurableEnvironment接口");}}// 處理所有的@ComponentScan注解Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);// 如果存在@ComponentScan注解,并且當(dāng)前階段不應(yīng)該跳過(guò)if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {// 循環(huán)處理每個(gè)@ComponentScan注解for (AnnotationAttributes componentScan : componentScans) {// 配置類(lèi)上存在@ComponentScan注解 -> 立即執(zhí)行掃描Set<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());// 檢查掃描結(jié)果中的定義集合,如果有進(jìn)一步的配置類(lèi),遞歸解析for (BeanDefinitionHolder holder : scannedBeanDefinitions) {if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());}}}}// 處理所有的@Import注解processImports(configClass, sourceClass, getImports(sourceClass), true);// 處理所有的@ImportResource注解AnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);// 如果@ImportResource注解存在if (importResource != null) {// 獲取資源位置String[] resources = importResource.getStringArray("locations");// 獲取資源的閱讀器類(lèi)Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");// 循環(huán)處理每個(gè)資源for (String resource : resources) {// 解析資源位置中的占位符String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);// 把解析后的資源添加到配置類(lèi)configClass.addImportedResource(resolvedResource, readerClass);}}// 處理單獨(dú)的@Bean方法Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);// 循環(huán)處理每個(gè)@Bean方法for (MethodMetadata methodMetadata : beanMethods) {// 添加@Bean方法到配置類(lèi)configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// 處理接口上的默認(rèn)方法processInterfaces(configClass, sourceClass);// 處理父類(lèi),如果存在的話if (sourceClass.getMetadata().hasSuperClass()) {// 獲取父類(lèi)名稱(chēng)String superclass = sourceClass.getMetadata().getSuperClassName();// 如果父類(lèi)存在,并且父類(lèi)不是java.*開(kāi)頭,并且尚未處理過(guò)if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {// 記錄已知的父類(lèi)this.knownSuperclasses.put(superclass, configClass);// 找到父類(lèi),返回其注解元數(shù)據(jù)并遞歸處理return sourceClass.getSuperClass();}}// 沒(méi)有父類(lèi) -> 處理完成return null;
}

到這里,大體流程我們已經(jīng)清楚。不再繼續(xù)針對(duì)注解的解析進(jìn)行講解,感興趣可以自行下載源碼閱讀理解。

五、本章小結(jié)

本章是對(duì)整 ConfigurationClassParser 進(jìn)行講解,它是 Spring framework 中的最核心類(lèi)。

到這里,Starter 的整個(gè)過(guò)程已經(jīng)分析完成,但是針對(duì)條件裝配,我們將在下一章進(jìn)行講解。

?已同步發(fā)布到公眾號(hào):面湯放鹽?第七節(jié) ConfigurationClassParser 源碼分析 (qq.com)

掘金賬號(hào):第七節(jié) ConfigurationClassParser 源碼分析 - 掘金 (juejin.cn)

http://aloenet.com.cn/news/46150.html

相關(guān)文章:

  • 做高端網(wǎng)站的網(wǎng)絡(luò)公司谷歌排名優(yōu)化入門(mén)教程
  • 有沒(méi)有免費(fèi)的網(wǎng)站軟件3步打造seo推廣方案
  • 太原做網(wǎng)站的通訊公司yy直播
  • 網(wǎng)站制作與網(wǎng)站建設(shè)實(shí)際報(bào)告百度競(jìng)價(jià)排名推廣
  • 怎么在百度知道做公司網(wǎng)站不收費(fèi)的小說(shuō)網(wǎng)站排名
  • 商務(wù)網(wǎng)站建設(shè)數(shù)據(jù)處理100個(gè)免費(fèi)推廣b站
  • 做網(wǎng)站圖片尺寸全球搜索引擎大全
  • python做網(wǎng)站源碼深圳網(wǎng)站營(yíng)銷(xiāo)seo費(fèi)用
  • 做3D打印樣品用什么外貿(mào)網(wǎng)站好2345網(wǎng)址大全
  • wordpress 登陸后查看seo引擎優(yōu)化
  • 長(zhǎng)沙手機(jī)網(wǎng)站開(kāi)發(fā)百度seo推廣計(jì)劃類(lèi)型包括
  • 建設(shè)網(wǎng)站合同2021百度熱搜年度榜
  • wordpress 中英文網(wǎng)站模板軟文寫(xiě)手接單平臺(tái)
  • 網(wǎng)站安全建設(shè)必要性seo搜索引擎專(zhuān)員
  • 昆山做網(wǎng)站找哪家好線上平臺(tái)推廣方式
  • 江蘇建設(shè)局的資質(zhì)辦理網(wǎng)站培訓(xùn)機(jī)構(gòu)最新消息
  • 素材網(wǎng)站建設(shè)需要多少費(fèi)用seo項(xiàng)目
  • win7下用iis搭建網(wǎng)站百度網(wǎng)盤(pán)客服電話
  • 上海定制網(wǎng)站建設(shè)費(fèi)用代寫(xiě)企業(yè)軟文
  • 做盜版網(wǎng)站違法嗎湖南網(wǎng)站設(shè)計(jì)
  • 模板做圖 網(wǎng)站有哪些友情鏈接平臺(tái)
  • 做餐飲在環(huán)保局網(wǎng)站備案手機(jī)網(wǎng)頁(yè)制作軟件
  • seo網(wǎng)站做推廣的公司輔導(dǎo)班培訓(xùn)機(jī)構(gòu)
  • 相冊(cè)管理網(wǎng)站模板外鏈怎么打開(kāi)
  • 做京東網(wǎng)站的摘要百度seo搜索引擎優(yōu)化方案
  • 找個(gè)公司做網(wǎng)站需要注意什么百家號(hào)seo怎么做
  • 163域名注冊(cè)屬于seo網(wǎng)站優(yōu)化
  • 企業(yè)營(yíng)銷(xiāo)網(wǎng)站建設(shè)規(guī)劃百度網(wǎng)站優(yōu)化公司
  • 怎么在網(wǎng)站上做視頻百度電腦版網(wǎng)頁(yè)
  • 設(shè)計(jì)一個(gè)網(wǎng)頁(yè)的策劃書(shū)怎么優(yōu)化網(wǎng)站排名才能起來(lái)