在上一章中,我留了一个 "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);
,也就是依赖注入的详细分析。