1.在ClassPathBeanDefinitionScanner类里,

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//****** bean name处理
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}

其中bean name 处理的语句:

String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

其中的generateBeanName由AnnotationBeanNameGenerator类提供
2.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);
}

会调用第二个return 来返回值,buildDefaultBeanName在AnnotationBeanNameGenerator中,代码如下:

(BeanDefinition definition, BeanDefinitionRegistry registry) {
return buildDefaultBeanName(definition);
}

其中return 语句的定义如下:

(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName);
}

其中return 语句调用的java.beans.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);
}

结论:如果类名的第一个字母和第二个字母都是大写字母,则直接以类名作为bean的名称,否则,把类名的第一个字母改成对应的小写字母,然后作为bean的名称

举例:
类名为Car,则生成的bean的名称为car,
类名为TShirt,则生成的bean的名称为TShirt

3.验证:
1)创建类,并用@Component标注

package cn.edu.tju.domain;

import org.springframework.stereotype.Component;

@Component
public class TShirt {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}

2)创建spring 配置文件:test3.xml

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">



<context:component-scan base-package="cn.edu.tju.domain"/>

</beans>

3)创建主类,并运行:

package cn.edu.tju;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestScan {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("test3.xml");
System.out.println("________________________________________________");
System.out.println("________________________________________________");

System.out.println(applicationContext.containsBean("tShirt"));
System.out.println(applicationContext.containsBean("TShirt"));
}
}

4)运行结果:

Spring: 通过@ComponentScan扫描到的类,默认会按什么规则生成bean name?_spring boot


4.在spring boot中通过@Bean标注的方法,以方法名作为bean name,同样也是按上述规则进行处理

1)定义bean

@Configuration
public class MyConfig {
@Bean
public RestTemplate getRestTemplate(){
RestTemplate restTemplate=new RestTemplateBuilder().setReadTimeout(Duration.ofSeconds(5))
.setConnectTimeout(Duration.ofSeconds(30)).build();
return restTemplate;
}
}

2)上述bean 在容器里的名称为: getRestTemplate