日韩性视频-久久久蜜桃-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的全部內容,希望文章能夠幫你解決所遇到的問題。

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