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

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代码:

	@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);
	}

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

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

其中return 语句的定义如下:

	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);
	}

其中return 语句调用的java.beans.decapitalize方法如下:

    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);
    }

结论:如果类名的第一个字母和第二个字母都是大写字母,则直接以类名作为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?_第1张图片
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

你可能感兴趣的:(Spring,spring,boot)