命名Spring Bean

Bean 的名称

每个Bean 拥有一个或多个标识符identifiers),这些标识符在Bean 所在的容器必须是唯一的, 但这里的唯一是指在其所在的BeanDefination或BeanFactory中是唯一的, 但并不是应用中是唯一的。

通常,一个Bean 仅有一个标识符,如果需要额外的,可考虑使用**别名(Alias)**来扩充。

在基于XML(不一定是基于XML文件, 也可能是网络资源) 的配置元信息中,开发人员可用id 或者name 属性来规定Bean 的标识符。

通常Bean 的标识符由字母组成,允许出现特殊字符。

如果要想引入Bean 的别名的话,可在name 属性使用半角逗号(“,”)或分号(“;”) 来间隔。

Bean 的id 或name 属性并非必须制定,如果留空的话,容器会为Bean 自动生成一个唯一的名称。

Bean 的命名尽管没有限制,不过官方建议采用驼峰的方式,更符合Java 的命名约定。

Bean 名称生成器(BeanNameGenerator)

• 由Spring Framework 2.0.3 引入,框架內建两种实现:

DefaultBeanNameGenerator:默认通用 BeanNameGenerator 实现
这里spring在一个小版本中引入了新的API, 在java中通常不允许这么做

AnnotationBeanNameGenerator:基于注解扫描的BeanNameGenerator 实现,起始于

Spring Framework 2.5,关联的官方文档:

With component scanning in the classpath, Spring generates bean names for unnamed components, following the rules described earlier:
essentially, taking the simple class name and turning its initial character to lower-case.
在classpath下进行组件扫描(@Component或@Controller等), spring会为没有指定name的组件生成bean的名称, 遵循过去的原则:
就是驼峰原则

However, in the (unusual) special case when there is more than one character and both the first and second characters are upper case, the original casing gets preserved.
如果有一个或多个首字母和第二个字母是大写的情况, 会采用另一个API

These are the same rules as defined by java.beans.Introspector.decapitalize (which Spring uses here).
java.beans.Introspector.decapitalize 是 javaBeans的 API

代码示例

/**
 * • Bean 名称生成器(BeanNameGenerator)
 * • 由Spring Framework 2.0.3 引入,框架內建两种实现:
 *      DefaultBeanNameGenerator:默认通用BeanNameGenerator 实现
 *      (这里注意spring的API引用方式不太符合java的标准, java是不允许在小版本, 比如这里的 2.0.3引入API的
 *      所以我们说spring2 是 针对 spring2.0~2.5的版本, 不限定于是对 spring2.0.0这个版本)
 *
 *      DefaultBeanNameGenerator 点进去可以看出来是一个单例, 但没有私有化构造器, 考虑到了老版本的兼容问题
 *      至于名字的生成规则, 看方法里面:
 *      if (isInnerBean) {
 * 			// Inner bean: generate identity hashcode suffix.
 * 		    //	内部bean, 类名 + # + 一串hashcode
 * 			id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ObjectUtils.getIdentityHexString(definition);
 *                }
 * 		else {
 * 			// Top-level bean: use plain class name with unique suffix if necessary.
 * 		    // 祖类bean, 类名 + 一串后缀如果有必要的话, 可以看uniqueBeanName()方法的实现
 * 			return uniqueBeanName(generatedBeanName, registry);
 *      }
 *
*      	public static String uniqueBeanName(String beanName, BeanDefinitionRegistry registry) {
 * 		    String id = beanName;
 * 		    int counter = -1;
 *
 * 		    // Increase counter until the id is unique.
 * 		    // 会在 BeanDefinitionRegistry 中计数, 如果已经有了, 会在类名 + # + 计数
 * 		    while (counter == -1 || registry.containsBeanDefinition(id)) {
 * 			    counter++;
 * 			    id = beanName + GENERATED_BEAN_NAME_SEPARATOR + counter;
 *          }
 * 		    return id;*
 * 		}
 *
 * • AnnotationBeanNameGenerator:基于注解扫描的BeanNameGenerator 实现,起始于
 *      Spring Framework 2.5,关联的官方文档:
 *      With component scanning in the classpath, Spring generates bean names for unnamed components,
 *      following the rules described earlier: essentially, taking the simple class name and turning its initial
 *      character to lower-case. However, in the (unusual) special case when there is more than one
 *      character and both the first and second characters are upper case, the original casing gets preserved.
 *      These are the same rules as defined by java.beans.Introspector.decapitalize (which Spring uses here).
 *      简单来说对于没有指定名称的Bean, 这里spring会按照驼峰来进行命名, 如果是特殊的, 比如连着两个大写字母的, 就会
 *      使用java.beans.Introspector.decapitalize这个API的规则
 *    AnnotationBeanNameGenerator显然是用来支持注解的, spring支持注解是从2.5开始的, 具体的实现看方法, 也是取得类名
 *
 *    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
 *        // 相较于以前, AnnotatedBeanDefinition是一个新的beanDefinition实现
 * 		  if (definition instanceof AnnotatedBeanDefinition) {
 * 			  String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
 * 			  if (StringUtils.hasText(beanName)) {
 * 				  // Explicit bean name found.
 * 				  return beanName;
 *            }
 *        }
 * 		  // Fallback: generate a unique default bean name.
 * 		  // 这里为了补偿老的API, 有一个补偿方法, 里面的实现与老的兼容
 * 		  return buildDefaultBeanName(definition, registry);
 * 	  }
 * */