/** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. */ @Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele){ return parseBeanDefinitionElement(ele, null); }
/** * Parses the supplied {@code <bean>} element. May return {@code null} * if there were errors during parse. Errors are reported to the * {@link org.springframework.beans.factory.parsing.ProblemReporter}. * * @param containingBean TODO 芋艿,需要进一步确认 */ @Nullable public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean){ // <1> 解析 id 和 name 属性 String id = ele.getAttribute(ID_ATTRIBUTE); String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
// <1> 计算别名集合 List<String> aliases = new ArrayList<>(); if (StringUtils.hasLength(nameAttr)) { String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS); aliases.addAll(Arrays.asList(nameArr)); }
// <3.1> beanName ,优先,使用 id String beanName = id; // <3.2> beanName ,其次,使用 aliases 的第一个 if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) { beanName = aliases.remove(0); // 移除出别名集合 if (logger.isTraceEnabled()) { logger.trace("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases"); } }
// <4> 解析属性,构造 AbstractBeanDefinition 对象 AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean); if (beanDefinition != null) { // <3.3> beanName ,再次,使用 beanName 生成规则 if (!StringUtils.hasText(beanName)) { try { if (containingBean != null) { // <3.3> 生成唯一的 beanName beanName = BeanDefinitionReaderUtils.generateBeanName( beanDefinition, this.readerContext.getRegistry(), true); } else { // <3.3> 生成唯一的 beanName beanName = this.readerContext.generateBeanName(beanDefinition); // TODO 芋艿,需要进一步确认 // Register an alias for the plain bean class name, if still possible, // if the generator returned the class name plus a suffix. // This is expected for Spring 1.2/2.0 backwards compatibility. String beanClassName = beanDefinition.getBeanClassName(); if (beanClassName != null && beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() && !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) { aliases.add(beanClassName); } } if (logger.isTraceEnabled()) { logger.trace("Neither XML 'id' nor 'name' specified - " + "using generated bean name [" + beanName + "]"); } } catch (Exception ex) { error(ex.getMessage(), ele); returnnull; } } // <5> 创建 BeanDefinitionHolder 对象 String[] aliasesArray = StringUtils.toStringArray(aliases); returnnew BeanDefinitionHolder(beanDefinition, beanName, aliasesArray); } returnnull; }
这个方法还没有对 bean 标签进行解析,只是在解析动作之前做了一些功能架构,主要的工作有:
<1> 处,解析 id、 name 属性,确定 aliases 集合
<2> 处,检测 beanName 是否唯一。代码如下:
/**
* 已使用 Bean 名字的集合
*
* Stores all used bean names so we can enforce uniqueness on a per
* beans-element basis. Duplicate bean ids/names may not exist within the
* same level of beans element nesting, but may be duplicated across levels.
*/
private final Set<String> usedNames = new HashSet<>();
/**
* Validate that the specified bean name and aliases have not been used already
* within the current level of beans element nesting.
*/
protected void checkNameUniqueness(String beanName, List<String> aliases, Element beanElement) {
// 寻找是否 beanName 已经使用
String foundName = null;
if (StringUtils.hasText(beanName) && this.usedNames.contains(beanName)) {
foundName = beanName;
}
if (foundName == null) {
foundName = CollectionUtils.findFirstMatch(this.usedNames, aliases);
}
// 若已使用,使用 problemReporter 提示错误
if (foundName != null) {
error("Bean name '" + foundName + "' is already used in this <beans> element", beanElement);
}
// 添加到 usedNames 集合
this.usedNames.add(beanName);
this.usedNames.addAll(aliases);
}