日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors

發布時間:2025/3/21 javascript 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • Pre
  • 細說invokeBeanDefinitionRegistryPostProcessors
    • 流程圖
    • 源碼分析
      • 解析配置類 parser.parse(candidates)
      • 配置類注冊到容器中 this.reader.loadBeanDefinitions(configClasses)
        • 注冊@Import的bean
        • 注冊@Bean的bean
        • 注冊@ImportResources的bean
        • 注冊ImportBeanDefinition的bean


Pre

Spring5源碼 - 04 invokeBeanFactoryPostProcessors 源碼解讀_1

Spring5源碼 - 05 invokeBeanFactoryPostProcessors 源碼解讀_2


細說invokeBeanDefinitionRegistryPostProcessors

前兩篇博文 我們過了一下這個方法的主干流程,其中有個關鍵的方法,我們沒有細說就是這個invokeBeanDefinitionRegistryPostProcessors。

這個方法很重要,本篇博文我們就一起來剖析下。

話不多說,還是下來梳理主干流程,然后再對著源碼過一遍


流程圖

我們來看流程圖


源碼分析

我們從頭跟一下

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

進入到AnnotationConfigApplicationContext的構造函數中

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {//調用構造函數this();//注冊我們的配置類register(annotatedClasses);//IOC容器刷新接口refresh();}

這里我們關注refresh方法,這個方法太重要了,里面非常深的調用鏈,我們這里先有個大概的認知

@Overridepublic void refresh() throws BeansException, IllegalStateException { //1:準備刷新上下文環境prepareRefresh();//2:獲取告訴子類初始化Bean工廠ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//3:對bean工廠進行填充屬性prepareBeanFactory(beanFactory);try {// 第四:留個子類去實現該接口postProcessBeanFactory(beanFactory);// 調用我們的bean工廠的后置處理器.invokeBeanFactoryPostProcessors(beanFactory);// 調用我們bean的后置處理器registerBeanPostProcessors(beanFactory);// 初始化國際化資源處理器.initMessageSource();// 創建事件多播器initApplicationEventMulticaster();// 這個方法同樣也是留個子類實現的springboot也是從這個方法進行啟動tomat的.onRefresh();//把我們的事件監聽器注冊到多播器上registerListeners();//實例化我們剩余的單實例bean.finishBeanFactoryInitialization(beanFactory);// 最后容器刷新 發布刷新事件(Spring cloud也是從這里啟動的)finishRefresh();}}

我們先重點關注【invokeBeanFactoryPostProcessors(beanFactory);】

跟進去,重點看 invokeBeanFactoryPostProcessors

//傳入bean工廠和獲取applicationContext中的bean工廠后置處理器(但是由于沒有任何實例化過程,所以傳遞進來的為空)PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

繼續,重點關注

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

這個方法就是我們今天要研究的源碼


/*** Invoke the given BeanDefinitionRegistryPostProcessor beans.*/private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {//獲取容器中的ConfigurationClassPostProcessor的后置處理器進行bean定義的掃描for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {postProcessor.postProcessBeanDefinitionRegistry(registry);}}

這里就一個,那就是 ConfigurationClassPostProcessor

僅需跟進去 ,看ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry方法

//真正的解析我們的bean定義processConfigBeanDefinitions(registry);

這個方法主要干的三件事兒

  • 找到開發人員傳入主配置類
  • 創建一個配置類解析器對象
  • 解析我們的配置類 parser.parse(candidates);
  • 把解析出來的配置類注冊到容器中 this.reader.loadBeanDefinitions(configClasses);
  • 我們重點關注第三步 和第四步

    先看第三步

    解析配置類 parser.parse(candidates)

    所以重點看

    parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());

    跟進去

    /*** 真的解析我們的配置類* @param metadata 配置類的源信息* @param beanName 當前配置類的beanName* @throws IOException*/protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {/*** 第一步:把我們的配置類源信息和beanName包裝成一個ConfigurationClass 對象*/processConfigurationClass(new ConfigurationClass(metadata, beanName));}

    進入

    關注

    sourceClass = doProcessConfigurationClass(configClass, sourceClass);

    這里面就是處理各種注解【@propertySource、@ComponentScan 、@Import、@ImportResource、@Bean】的地方,我們來看下源碼

    @Nullableprotected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)throws IOException {// Recursively process any member (nested) classes firstprocessMemberClasses(configClass, sourceClass);//處理我們的@propertySource注解的for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);}else {logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");}}//解析我們的 @ComponentScan 注解//從我們的配置類上解析處ComponentScans的對象集合屬性Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {//循環解析 我們解析出來的AnnotationAttributesfor (AnnotationAttributes componentScan : componentScans) {//把我們掃描出來的類變為bean定義的集合 真正的解析Set<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());//循環處理我們包掃描出來的bean定義for (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}//判斷當前掃描出來的bean定義是不是一個配置類,若是的話 直接進行遞歸解析if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {//遞歸解析parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// 處理 @Import annotationsprocessImports(configClass, sourceClass, getImports(sourceClass), true);// 處理 @ImportResource annotationsAnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// 處理 @Bean methods 獲取到我們配置類中所有標注了@Bean的方法Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// 處理配置類接口的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);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}}// 沒有父類解析完成return null;}

    配置類注冊到容器中 this.reader.loadBeanDefinitions(configClasses)

    第三步完成了,我們來看下這一步Spring是如和把配置類注冊到容器中的

    public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();//注冊我們的配置類到容器中for (ConfigurationClass configClass : configurationModel) {loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}}

    那自然就是

    loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);

    很清晰哈

    一個個的看下吧

    注冊@Import的bean

    private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {//獲取我們的配置類的源信息AnnotationMetadata metadata = configClass.getMetadata();//構建為我們的bean定義AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);//設置他的scopeScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);configBeanDef.setScope(scopeMetadata.getScopeName());//獲取bean的名稱String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);//處理我們的JRS250組件的AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);//注冊我們的bean定義到我們的容器中this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());configClass.setBeanName(configBeanName);if (logger.isDebugEnabled()) {logger.debug("Registered bean definition for imported class '" + configBeanName + "'");}}

    重點就是

    this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());

    注冊@Bean的bean

    處理@Bean可以跟的各種屬性


    注冊@ImportResources的bean

    private void loadBeanDefinitionsFromImportedResources(Map<String, Class<? extends BeanDefinitionReader>> importedResources) {// reader實例緩存Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();// 循環處理<配置文件路徑-reader>importedResources.forEach((resource, readerClass) -> {// 如果注解配置的Reader是默認的(我們一般其實也不改)if (BeanDefinitionReader.class == readerClass) {if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {// 如果文件名是.groovy結尾,則使用GroovyBeanDefinitionReader// 說實話我也第一次知道還可以用groovy腳本來做spring的配置文件// 后面我去看了一下BeanDefinitionReader這個接口的實現類,發現還一個// PropertiesBeanDefinitionReader,感興趣的同學可以去研究一下readerClass = GroovyBeanDefinitionReader.class;}else {// 默認情況下我們使用XmlBeanDefinitionReader readerClass = XmlBeanDefinitionReader.class;}}// 先從緩存拿BeanDefinitionReader reader = readerInstanceCache.get(readerClass);if (reader == null) {try {// 拿不到就新建一個,配置的reader類必須有一個只有BeanDefinitionRegistry參數的構造器reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);// Delegate the current ResourceLoader to it if possibleif (reader instanceof AbstractBeanDefinitionReader) {AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);abdr.setResourceLoader(this.resourceLoader);abdr.setEnvironment(this.environment);}readerInstanceCache.put(readerClass, reader);}catch (Throwable ex) {throw new IllegalStateException("Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");}}// 使用reader從文件加載beanreader.loadBeanDefinitions(resource);}); }

    默認情況下 是創建一個XmlBeanDefinitionReader來解析加載我們的配置文件中定義的bean的。


    注冊ImportBeanDefinition的bean

    private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {registrars.forEach((registrar, metadata) ->registrar.registerBeanDefinitions(metadata, this.registry));}

    很直觀了哈 ,循環直接調用ImportBeanDefinitionRegistrar.registerBeanDefinitions方法進行beanDefinition的注冊。


    總結

    以上是生活随笔為你收集整理的Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 男人的天堂色 | av色图片| 亚洲第一成肉网 | 中文字幕一区二区三区四区免费看 | 国产又粗又硬视频 | 男人喷出精子视频 | 欧美 日韩 国产 成人 在线 91 | 99热r| 亚洲天堂手机版 | 91鲁| 九九热视频在线观看 | 91成人综合 | 久久99操 | 色综合99 | 在线超碰 | 豆花av在线 | 永久免费在线视频 | cao我| 香蕉福利视频 | 伊人3 | 日本天堂网在线观看 | av网站在线看 | 新婚之夜玷污岳丰满少妇在线观看 | 四虎视频国产精品免费入口 | 牛牛电影国产一区二区 | 欧美成人午夜视频 | 欧美动态色图 | 久久这里只有精品23 | 娇妻之欲海泛舟无弹窗笔趣阁 | 小镇姑娘国语版在线观看免费 | 欧洲av片| 亚洲免费毛片 | 国产a级一级片 | 人人妻人人爽欧美成人一区 | 国产色秀视频 | 精品人妻少妇嫩草av无码 | 成人做爰免费视频免费看 | 欧美天堂一区 | 久久国产影院 | 日韩精品免费一区二区在线观看 | 色欲久久久天天天综合网 | 国产精品成人免费看片 | 夜夜天堂| 色综合久久久久无码专区 | 欧美色图视频在线 | 国产.com | 日本免费黄色网 | 中文字幕一区二区三区人妻在线视频 | 99热99re6国产在线播放 | 日本一区视频在线观看 | 九色蝌蚪9l视频蝌蚪9l视频 | 嫩草视频一区二区三区 | 欧美视频一区在线 | www.com捏胸挤出奶 | 精彩视频一区二区 | 日本欧美一区二区三区不卡视频 | 日本一区二区观看 | 国产日本视频 | 国偷自产av一区二区三区 | 阿v天堂在线观看 | 亚洲一区在线观 | 天天射日| juliaannxxxxx高清| 免费午夜人成电影 | 亚洲av日韩av永久无码下载 | 国产精品传媒一区二区 | 午夜av中文字幕 | 久久人人干 | 在线播放不卡 | av网站大全免费 | 又大又粗欧美黑人aaaaa片 | 黄色三级小说 | 一区二区三区在线免费 | 免费在线观看视频a | 久久性av| 精品人妻人人做人人爽夜夜爽 | 黄网av| 国产免费av一区二区三区 | 韩日精品中文字幕 | 一区二区三区日韩欧美 | 人人妻人人爽欧美成人一区 | 亚洲大乳 | 啪免费| 天堂中文网 | 国产欧美一区二区三区在线 | 亚洲不卡在线视频 | 丁香六月综合激情 | 蜜桃视频导航 | 成人高潮片免费视频 | 麻豆tv在线 | 久久久高清 | 中文字幕dvd | 丰满少妇一区二区三区专区 | 久久综合激情网 | 日本人六九视频 | 日本黄色不卡视频 | 都市激情国产精品 | 亚欧激情 | 五月婷婷激情网 |