Spring 中 Bean 注册疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
liuyunlong
V2EX    Java

Spring 中 Bean 注册疑问

  •  
  •   liuyunlong
    1713612859 2023-08-30 10:31:44 +08:00 1870 次点击
    这是一个创建于 775 天前的主题,其中的信息可能已经有所发展或是发生改变。

    DefaultListableBeanFactory #registerBeanDefinition(String beanName,BeanDefintion bean);

    疑问 1:

     @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitiOns= new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitiOnNames= updatedDefinitions; removeManualSingletonName(beanName); } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitiOnNames= null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); } } 

    其中这一段代码

     if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitiOns= new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitiOnNames= updatedDefinitions; removeManualSingletonName(beanName); } } 

    不太明白为啥还得判断容器是否存活,但是断点下来确实走的 else

     else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } 

    希望大家能给解答一下,万分感谢 !

    shanghai1943
        1
    shanghai1943  
       2023-08-30 10:50:10 +08:00   2
    claude ai 的回复


    hasBeanCreationStarted() 方法是用来判断 bean 定义注册是否处于启动阶段。

    在 Spring 容器启动时,会有一个 bean 定义注册的过程,这个过程称为启动阶段。启动阶段结束后,会调用 finishBeanFactoryInitialization() 方法,设置启动阶段完成的标记。

    之所以需要判断启动阶段,是因为在启动阶段和非启动阶段,bean 定义的注册逻辑有略微不同:

    1. 启动阶段:可以直接修改 beanDefinitionMap 和 beanDefinitionNames

    2. 非启动阶段:需要同步处理,避免多线程并发访问这些容器内存状态

    else 分支就是处理非启动阶段的逻辑。当容器已经完成了启动,这个时候再注册 bean 定义,就需要加锁处理:

    1. 同步包装 beanDefinitionMap 的修改

    2. 创建 beanDefinitionNames 的拷贝进行修改

    3. 删除 manualSingletonNames 里的对应名称

    之所以这么设计,是因为启动阶段内存状态的变更频繁,如果都加锁处理会非常低效。所以启动阶段只 simply 修改状态,结束后再对状态变更加锁。

    而 hasBeanCreationStarted()就是判断当前是否还在启动阶段,从而决定走哪种 bean 定义注册逻辑。

    所以这个判断对提高整个容器的并发性能很重要。
    liuyunlong
        2
    liuyunlong  
    OP
       2023-08-30 11:22:34 +08:00
    清晰明了,万分感谢
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3562 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 94ms UTC 04:32 PVG 12:32 LAX 21:32 JFK 00:32
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86