前言
用了多年spring,始终想当然把spring默认的beanName当成是类名的首字母小写,比方HelloService其beanName为helloService。直到有天对接了供方厂商的接口,他有个类形如ABService,于是用
getBean(“aBService”)
的形式获取bean,后果取到是null,一开始认为是ABservice没注入,前面采纳
getBean(ABService.class)
能胜利获取到bean,阐明ABService是有注入到IOC容器中,然而为啥用aBService获取不到bean?于是就用如下代码段,打印出相应ABService对应的beanName
applicationContext.getBeansOfType(ABService.class).forEach((beanName,bean)->{
System.out.println(beanName + ":" + bean);
});
打印进去的后果,如下
ABService:com.github.lybgeek.ABService@245b6b85
beanName居然是ABService,这就和之前的想当然有出入。于是只好查看源码
源码查看
源码查看有2种形式,本文的示例是springboot我的项目
办法一:从main办法间接调试断点
从图能够看出如果是以扫描注解注入模式,其beanName的生成规定是由
org.springframework.context.annotation.AnnotationBeanNameGenerator#generateBeanName
决定。
ps: 这种间接从main启动类调试起,比拟实用于工夫比拟多,或者排查毫无脉络
办法二:带着问题查看,靠猜加验证的形式
利用idea的find Usage查找援用,比方ABService的注解@service,咱们能够间接查看哪个援用到@Service,再猜想下beanName的生成规定
通过猜,咱们基本上就能够定位出比拟合乎咱们需要的办法
源码验证
从下面的剖析,咱们能够晓得如果是扫描bean注解注入的形式,其生成beanName规定,是在
org.springframework.context.annotation.AnnotationBeanNameGenerator
其生成规定代码如下
@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);
}
从代码段,咱们能够看出,注解上有取名,比方@Service(“abService”),则beanName为abService,如果没有取名,则看
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);
}
其实从代码咱们就很容易看出答案了,如果类名前两个或以上个字母都是大写,则beanName和类名就一样了,不会进行首字母小写转换。
decapitalize这个办法的正文也写得很分明,正文如下
/**
* 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.
*/
总结
通过扫描bean注解注入IOC时,如果不指定bean名称的默认规定是类名的首字母小写,如果类名前两个或以上个字母都是大写,那么bean名称与类名一样。
其实这个细节可能懂的都懂,本文的彩蛋次要是分享一下平时查看源码的一点心得吧,哈哈
发表回复