向容器中注册 BeanDefinition
这部分从 DefaultBeanDefinitionDocumentReader 中的processBeanDefinition方法说起:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
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));
}
}
在解析完成之后,负责将 BeanDefinition 注册到容器中的是这样代码:
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
传入方法的参数,一个是之前解析道的 BeanDefinitionHolder,另一个其实就是我们最初创建的 BeanFactory(这里为什么是最初创建的 BeanFactory ?分析如下:)。
这里的registry就是我们起初创建的 BeanFacoty,之前涉及到的流程已经很多了,这里再捋一下起初创建的 BeanFacoty 是怎么到这儿的。
在AbstractApplicationContext的refresh方法中,调用了obtainFreshBeanFactory方法,其中的refreshBeanFactory方法通过createBeanFactory方法创建了一个 DefaultListableBeanFactory,并赋值给了beanFactory成员变量。
在解析 XML 文件之前,AbstractXmlApplicationContext的loadBeanDefinitions方法中,创建 XmlBeanDefinitionReader 的时候,通过构造方法,将beanFactory赋值给了其registry成员变量,这一步通过其父类 AbstractBeanDefinitionReader 的构造方法完成。
在 XmlBeanDefinitionReader 的registerBeanDefinitions方法中,通过createBeanDefinitionDocumentReader方法创建了 DefaultBeanDefinitionDocumentReader 类型的变量documentReader,并在调用documentReader的registerBeanDefinitions方法时,通过createReaderContext创建了一个 XmlReaderContext 作为方法的参数传递给了documentReader并赋值给了其readerContext成员变量。
上一步中,createReaderContext方法中,将当前对象也就是 XmlBeanDefinitionReader 对象作为参数传入并赋值给了reader成员变量,而 DefaultBeanDefinitionDocumentReader 调用getReaderContext().getRegistry()方法的时候,getReaderContext获取到的是之前创建的 XmlReaderContext 对象,getRegistry方法实际逻辑是this.reader.getRegistry(),其中的this.reader就是 XmlBeanDefinitionReader,因为 XmlBeanDefinitionReader 的beanFactory成员变量就是起初创建的 BeanFactory。
因此这里得到的就是最初创建的BeanFactory
我们跳进方法里看源码:
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
这里的关键步骤是registry.registerBeanDefinition方法的调用。也就是 DefaultListableBeanFactory 中的registerBeanDefinition方法:
@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");
// 第一部分,对 BeanDefinition 进行注册前的检查
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
// 第二部分,注册 BeanDefinition
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("...");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("...");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("...");
}
}
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();
}
}
以上两个方法就是注册 BeanDefination 的整个流程,代码比较长,先大概捋一下流程,再分开详细讲解。在代码里我通过注释把代码大体分为两部分:
1.对 BeanDefinition 进行注册前的检查
2.注册 BeanDefinition
下面分别深入分析。
###注册前的检查
这部分涉及到的代码主要是validate方法的调用:
public void validate() throws BeanDefinitionValidationException {
if (hasMethodOverrides() && getFactoryMethodName() != null) {
throw new BeanDefinitionValidationException("...");
}
if (hasBeanClass()) {
prepareMethodOverrides();
}
}
先看第一个if语句的判断条件。
hasMethodOverrides()方法获取到的是!this.methodOverrides.isEmpty()。这里简单介绍一下methodOverrides是什么。在将 XML 配置解析成 BeanDefinition 的时候,bean标签的lookup-method和replaced-method会被分别解析成 LookupOverride 和 ReplaceOverride 对象,添加到 BeanDefinition 的methodOverrides成员变量中。它们的作用是通过配置来覆盖 Bean 原有的方法实现。
getFactoryMethodName()获取到的是 XML 在bean标签上配置的用来创建 Bean 的工厂方法。
这个if语句是为了确保,上述两者不能共存,否则就会报错。这是因为,如果给一个 Bean 配置了工厂方法,那么它会由工厂方法来创建,而不是 Spring 默认的方式创建,这种情况下无法进行方法的覆盖。因此,这里的判断是为了确保配置信息没有出现冲突。
再看第二个if语句,判断条件hasBeanClass()在我们分析的流程中肯定会返回true,因此我们直接看语句块中的prepareMethodOverrides()方法调用。
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
// Check that lookup methods exist and determine their overloaded status.
if (hasMethodOverrides()) {
getMethodOverrides().getOverrides().forEach(this::prepareMethodOverride);
}
}
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
if (count == 0) {
throw new BeanDefinitionValidationException("");
}
else if (count == 1) {
// Mark override as not overloaded, to avoid the overhead of arg type checking.
mo.setOverloaded(false);
}
}
这里针对配置了 MethodOverrides 的 BeanDefinition,从 Bean 对应的类中获取同名的方法,也就是要被覆盖的方法。
如果找不到,则报错,因为这算是一个配置错误。
如果需要被覆盖的方法同名方法在类中之存在 1 个,说明在类中没有它的重载方法,则将 MethodOverride 的overloaded属性设置为false。这一步是为了告诉 Spring 在覆盖方法的时候,不需要再去检查 Bean 中是否有其他的重载方法了,算是一个性能上的优化。
###注册 BeanDefinition
接下来回到 DefaultListableBeanFactory 的registerBeanDefinition方法的第二部分,开始进入注册 BeanDefinition 的流程。
首先,会从beanDefinitionMap容器中根据当前 BeanDefinition 中配置的beanName查找已经存在的 BeanDefinition:
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
因为我们这里分析的是初始化的流程,beanDefinitionMap应该是空的,所以这里是获取不到已有的 BeanDefinition 的,并且目前是注册 BeanDefinition 的阶段,Bean 的创建也没有开始,所以,我们可以省略掉对应的逻辑,直接看注册的逻辑:
// 第二部分,注册 BeanDefinition
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
/* 前已经存在同名的 BeanDefinition 的逻辑*/
}
else {
if (hasBeanCreationStarted()) {
/* 已经开始 Bean 创建的逻辑 */
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
}
这里就很简单了,将beanDefinition和beanName分别添加到对应的集合中即可。
###处理别名
DefaultListableBeanFactory 的registerBeanDefinition方法执行完之后,又会回到 BeanDefinitionReaderUtils 的registerBeanDefinition中的后半部分代码:
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
可以看出这里的流程是为了处理 BeanDefinition 的别名,我们跳到registerAlias方法去看一下,根据 DefaultListableBeanFactory 的继承关系,这个方法的实现可以在 SimpleAliasRegistry 中找到:
public void registerAlias(String name, String alias) {
Assert.hasText(name, "'name' must not be empty");
Assert.hasText(alias, "'alias' must not be empty");
synchronized (this.aliasMap) {
if (alias.equals(name)) {
this.aliasMap.remove(alias);
if (logger.isDebugEnabled()) {
logger.debug("...");
}
}
else {
String registeredName = this.aliasMap.get(alias);
if (registeredName != null) {
if (registeredName.equals(name)) {
// An existing alias - no need to re-register
return;
}
if (!allowAliasOverriding()) {
throw new IllegalStateException("...");
}
if (logger.isDebugEnabled()) {
logger.debug("...");
}
}
checkForAliasCircle(name, alias);
this.aliasMap.put(alias, name);
if (logger.isTraceEnabled()) {
logger.trace("...");
}
}
}
}
方法中的逻辑如下:
如果beanName和别名相同,则将别名从aliasMap中移除
根据别名从aliasMap找到对应的beanName
如果可以找到,说明之前注册过了,直接返回,不执行后面的逻辑
如果找不到,就判断是不是允许别名覆盖,不允许就抛出异常
检查别名循环
将别名和beanName的对应关系添加到aliasMap中(包括允许覆盖的情况)
整体逻辑比较简单,下面看一下检查别名循环的方法checkForAliasCircle:
protected void checkForAliasCircle(String name, String alias) {
if (hasAlias(alias, name)) {
throw new IllegalStateException("Cannot register alias '" + alias +
"' for name '" + name + "': Circular reference - '" +
name + "' is a direct or indirect alias for '" + alias + "' already");
}
}
public boolean hasAlias(String name, String alias) {
String registeredName = this.aliasMap.get(alias);
return ObjectUtils.nullSafeEquals(registeredName, name) || (registeredName != null
&& hasAlias(name, registeredName));
}
这里的逻辑也比较简单,举个例子就是,检查是不是存在一个beanName是a别名是b的 Bean,同时又存在一个beanName是b别名是a的Bean。如果有就抛出异常。
###后续
至此,Spring 加载 BeanDefinition 的过程就全部分析完了,可以说这是 BeanFactory 初始化过程中最复杂的步骤。初始化完 BeanFactory 之后,就有了一个初级的容器。