在上一章中,我留了一个 "BeanDefinition注册到registry" 的尾巴还没分析,这边我把代码入口从新放到下面,以便于回顾:java
/** * 经过解析器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()
ide
还记得咱们第四章分析的:建立读取器上下文的代码么,读取器上下文内部是封装了读取器实例的,这就意味着咱们可以经过上下文获取到读取器。工具
紧接着,咱们在第一章分析的,建立读取器时会传入一个 registry 类型的参数,所以经过读取器咱们又可以获取到 registry。ui
所以,咱们就可以经过读取器上下文获取到 registry。this
BeanDefinitionReaderUtils.registerBeanDefinition()spa
这里是调用了一个工具类来实现注册的流程线程
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());
这部分的逻辑:debug
因为对于 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);
,也就是依赖注入的详细分析。