在上一章中,我留了一个 "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到工厂,首先我们得获取到工厂,这里是通过读取器上下文来获取到的 getReaderContext().getRegistry()
还记得我们第四章分析的:创建读取器上下文的代码么,读取器上下文内部是封装了读取器实例的,这就意味着我们能够通过上下文获取到读取器。
紧接着,我们在第一章分析的,创建读取器时会传入一个 registry 类型的参数,因此通过读取器我们又能够获取到 registry。
因此,我们就能够通过读取器上下文获取到 registry。
这里是调用了一个工具类来实现注册的流程
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-value到map中
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);
,也就是依赖注入的详细分析。