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

Spring 中 Bean 注册疑问

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

    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   ·   实用小工具   ·   2406 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 02:11 · PVG 10:11 · LAX 18:11 · JFK 21:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.