透过Spring源码查看Bean的命名转换规则

 透过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。


邓棋文 2023-10-21