【超详细的Spring源码分析 —— 05 Spring对于Bean管理的核心组件源码分析 – 注册Bean Definition】

在上一章中,我留了一个 "BeanDefinition注册到registry" 的尾巴还没分析,这边我把代码入口重新放到下面,以便于回顾:

/**
 * 通过解析器delegate去处理给定的bean element, 并解析出相应的bean Definition, 注册到工厂中
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 通过delegate解析bean定义, 获取到一个BeanDefinitionHolder实例
    // 这个实例, 其实就代表了xml文件中的一个完整的bean标签对应的Bean Definition
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    
    // 如果bdHolder不为空, 说明解析成功了, 之后就是注册环节了
    // 注册环节我们留着在下一篇中详细展开
    if (bdHolder != null) {
    	bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    	try {
            // 注册最终的BeanDefinition到工厂
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    	}
    	catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
    	}
    	// Send registration event.
    	getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}
复制代码

我们要关注的是: BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

一、注册最终的BeanDefinition到工厂

要注册BeanDefinition到工厂,首先我们得获取到工厂,这里是通过读取器上下文来获取到的 getReaderContext().getRegistry()

还记得我们第四章分析的:创建读取器上下文的代码么,读取器上下文内部是封装了读取器实例的,这就意味着我们能够通过上下文获取到读取器。

紧接着,我们在第一章分析的,创建读取器时会传入一个 registry 类型的参数,因此通过读取器我们又能够获取到 registry。

因此,我们就能够通过读取器上下文获取到 registry。

BeanDefinitionReaderUtils.registerBeanDefinition()

这里是调用了一个工具类来实现注册的流程

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
    // 获取到Bean的唯一标识
    String beanName = definitionHolder.getBeanName();
    // 重点!!!!
    // 将 bean 定义真正注册到 Bean 工厂中
    registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    
    // 如果存在别名, 那么会注册别名
    String[] aliases = definitionHolder.getAliases();
    if (aliases != null) {
    	for (String alias : aliases) {
            registry.registerAlias(beanName, alias);
    	}
    }
}
复制代码

我们接着深入到 registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
这部分的逻辑:

由于对于 registry 的实现是采用的 —— DefaultListableBeanFactory,因此我们看看这个类对于 registerBeanDefinition() 的实现即可。

下面的代码有些长,我们挑关键的部分分析即可:

@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
    // 唯一标识不能为空
    Assert.hasText(beanName, "Bean name must not be empty");
    // 确保Bean定义不能为空
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    
    // 如果Bean定义是 AbstractBeanDefinition 类型, 那么会进行一个验证逻辑
    if (beanDefinition instanceof AbstractBeanDefinition) {
    	try {
            ((AbstractBeanDefinition) beanDefinition).validate();
    	}
    	catch (BeanDefinitionValidationException ex) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex);
    	}
    }
    
    // 我们的Bean定义是挨个被解析然后注册到工厂中的
    // 这就意味着工厂中可能已经存在其他Bean定义
    
    // 因此这里会先尝试从工厂中获取一下我们要注册的bean定义
    // 确保工厂中是不存在这个bean定义的
    // 这里存放 唯一标识+BeanDefinition 的容器beanDefinitionMap是 concurrentHashMap
    BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
    // 如果已经存在相应的唯一标识了
    if (existingDefinition != null) {
        // 那么为判断是否允许 BeanDefinition 的覆盖
        // 如果不允许就抛出异常
    	// 一般都是不允许的
    	if (!isAllowBeanDefinitionOverriding()) {
    		throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
    	}
    	// 如果允许覆盖, 那么会进行一个bean定义角色的判断
    	// 如果已经存在的bean定义的角色小于当前要存放bean定义的角色, 那么会进行一个日志打印
    	// 一般在开发中也很少会进入这个逻辑
    	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 + "]");
    		}
    	}
    	// 如果二者(已经存在的bean定义和要覆盖的bean定义)不相同
    	// 那么打印一个日志
    	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 + "]");
    		}
    	}
    	
    	// 进行一个bean定义的覆盖,放置key-valuemap中
    	this.beanDefinitionMap.put(beanName, beanDefinition);
    }
    else { // 如果 concurrentHashMap 中不存在相应的bean定义键值对
    	// 那么会检查这个工厂中bean的创建阶段是否已经启动
    	// 也就是这个工厂中的所有bean它是否被标记为 created
    	// 如果已经启动
    	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)) {
        // 重置 BeanDefinition 缓存的处理
    	resetBeanDefinition(beanName);
    }
}
复制代码

当上面这个方法执行完毕后,工厂中的 BeanDefinitionMap 这个容器就已经存放了一个key-value键值对,key=唯一标识、value=beanDefinition。

当整个解析、注册的事件处理完毕后,我们返回到一开始给出的那个方法中:

/**
 * 通过解析器delegate去处理给定的bean element, 并解析出相应的bean Definition, 注册到工厂中
 */
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    // 通过delegate解析bean定义, 获取到一个BeanDefinitionHolder实例
    // 这个实例, 其实就代表了xml文件中的一个完整的bean标签对应的Bean Definition
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    
    // 如果bdHolder不为空, 说明解析成功了, 之后就是注册环节了
    // 注册环节我们留着在下一篇中详细展开
    if (bdHolder != null) {
    	bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    	try {
            // 注册最终的BeanDefinition到工厂
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    	}
    	catch (BeanDefinitionStoreException ex) {
            getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, ex);
    	}
    	// 发送事件
    	getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }
}
复制代码

我们看到最后执行的方法: getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

这里采用了一个观察者模式,当特定的事件触发(成功完成Bean定义的解析、注册),那么会调用观察者类(读取器上下文)的方法,执行一些特定逻辑。

二、总结

那么这里,整个 Spring 对 Bean 的解析、装配流程就分析完毕了。从宏观上来看, beanDefinitionReader.loadBeanDefinitions()
这个逻辑就完成了。 但要注意,截止到目前,我们只是在工厂中注册了Bean Definition,并没有对其完成一个实例化的过程。
实例化的过程还要在后续的逻辑中才开始执行。

由此可见,Spring 对外提供的 API 接口仅仅是冰山一角,底层的实现就如同大海一样深不可测。

那么在下一章将带来: defaultListableBeanFactory.getBean("student", Student.class);
,也就是依赖注入的详细分析

原文 

https://juejin.im/post/5f0152d06fb9a07e80203a1a

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » 【超详细的Spring源码分析 —— 05 Spring对于Bean管理的核心组件源码分析 – 注册Bean Definition】

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址