透过Spring源码查看Bean的命名转换规则
Spring作为Java最流行的开源框架之一,其中Bean的使用是至关重要的一部分。然而,我们在使用Spring Bean时,经常会忽略Bean名称的一些转换规则。这篇文章,就让我们深入Spring源码,一起探讨一下Spring Bean的命名转换规则。
在Spring中,每个Bean都有一个独一无二的id,这就是我们所说的Bean的名称。但是,如果我们在定义Bean时没有显式地指定id,那么Spring就会根据一些规则来自动生成一个。
那么,Spring是如何自动生成Bean的名称的呢?这就涉及到Spring的两个核心类:`BeanDefinitionReaderUtils`和`ClassUtils`。
在`BeanDefinitionReaderUtils`类的`generateBeanName`方法中,如果我们没有为Bean指定id,Spring会调用这个方法来自动生成一个。具体如下:
```java
public static String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
String generatedBeanName = definition.getBeanClassName();
if (generatedBeanName == null) {
if (registry instanceof ConfigurableBeanFactory) {
generatedBeanName = ((ConfigurableBeanFactory) registry).resolveEmbeddedValue(definition.getFactoryBeanName());
} else {
generatedBeanName = definition.getFactoryBeanName();
}
}
if (!StringUtils.hasText(generatedBeanName)) {
throw new BeanDefinitionStoreException("Unnamed bean definition specifies neither 'class' nor 'name' nor 'factory-bean-name' - can't generate bean name");
}
String id = generatedBeanName;
if (definition instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) definition).hasBeanClass()) {
id = generatedBeanName + GENERATED_BEAN_NAME_SEPARATOR + ClassUtils.getShortNameAsProperty(((AbstractBeanDefinition) definition).getBeanClass());
}
return uniqueBeanName(id, registry);
}
```
可以看到,Spring首先会尝试使用Bean的完全限定名作为Bean的id。如果Bean的定义中既没有指定类名,也没有指定工厂Bean的名称,那么Spring就会抛出异常。
然后,如果Bean的定义是一个具体的类,那么Spring会将类名转换为属性名,然后与类的完全限定名一起作为Bean的id。类名转换为属性名的逻辑在`ClassUtils`类的`getShortNameAsProperty`方法中:
```java
public static String getShortNameAsProperty(Class<?> clazz) {
return Introspector.decapitalize(getShortName(clazz));
}
```
这个方法会调用Java内置的`Introspector.decapitalize`方法将类名的首字母转换为小写。
所以,如果我们在定义Bean时没有显式地指定id,那么Spring会自动生成一个形如`com.example.MyBean#myBean`的id。