Talk about the naming of spring bean names

linyb極客之路發表於2021-06-24

Preface

After using spring for many years, I have always assumed that the default beanName of spring is the lowercase of the first letter of the class name. For example, the beanName of HelloService is helloService. Until one day when the supplier’s interface was docked, he had a class like ABService, so he used

getBean(“aBService”) 

The way to get the bean, the result is null, at first I thought it was that ABservice was not injected, and then used

getBean(ABService.class) 

The bean can be successfully obtained, indicating that ABService is injected into the IOC container, but why can’t I get the bean with aBService? So use the following code snippet to print out the beanName corresponding to the corresponding ABService

 applicationContext.getBeansOfType(ABService.class).forEach((beanName,bean)->{
            System.out.println(beanName + ":" + bean);
        });

The printed result is as follows

ABService:com.github.lybgeek.ABService@245b6b85

The beanName turned out to be ABService, which is different from the previous assumption. So I had to view the source code

Source View

There are two ways to view the source code, the example in this article is the springboot project

Method 1: Debug the breakpoint directly from the main method

beanName.jpg
It can be seen from the figure that if it is in the form of scanning annotation injection, the generation rule of its beanName is determined by

org.springframework.context.annotation.AnnotationBeanNameGenerator#generateBeanName

Decided.

ps: starts directly from the main startup type debugging, which is more suitable for more time, or the investigation has no clue

Method 2: Check with questions and rely on guessing and verifying

Use the find Usage of idea to find references, such as the annotation @service of ABService, we can directly check which references to @Service, and then guess the generation rule of beanName
在這裡插入圖片描述
By guessing, we can basically locate a method that meets our needs

Source code verification

From the above analysis, we can know that if the method of scanning bean annotation injection is to generate the beanName rule, it is in

org.springframework.context.annotation.AnnotationBeanNameGenerator

The generation rule code is as follows

@Override
    public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
        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.
        return buildDefaultBeanName(definition, registry);
    }

From the code snippet, we can see that the annotation has a name, such as @Service ("abService"), the beanName is abService, if there is no name, then look

protected String buildDefaultBeanName(BeanDefinition definition) {
        String beanClassName = definition.getBeanClassName();
        Assert.state(beanClassName != null, "No bean class name set");
        String shortClassName = ClassUtils.getShortName(beanClassName);
        return Introspector.decapitalize(shortClassName);
    }
public static String decapitalize(String name) {
        if (name == null || name.length() == 0) {
            return name;
        }
        if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                        Character.isUpperCase(name.charAt(0))){
            return name;
        }
        char chars[] = name.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return new String(chars);
    }

In fact, we can easily see the answer from the code, If the first two or more letters of the class name are uppercase, the beanName and the class name are the same, and the first letter will not be converted to lowercase.

The comment of the decapitalize method is also very clearly written, as follows

/**
     * Utility method to take a string and convert it to normal Java variable
     * name capitalization.  This normally means converting the first
     * character from upper case to lower case, but in the (unusual) special
     * case when there is more than one character and both the first and
     * second characters are upper case, we leave it alone.
     * <p>
     * Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
     * as "URL".
     *
     * @param  name The string to be decapitalized.
     * @return  The decapitalized version of the string.
     */

to sum up

When injecting IOC by scanning bean annotations, if you do not specify the bean name, the default rule is to lowercase the first letter of the class name. If the first two or more letters of the class name are uppercase, then the bean name is the same as the class name.

In fact, you may understand all the details. The easter eggs in this article are mainly to share some experience of viewing the source code, haha

相關文章