详解关于spring bean名称命名的那些事

网友投稿 263 2022-12-29

详解关于spring bean名称命名的那些事

目录前言02源码查看01从main方法直接调试断点02带着问题查看,靠猜加验证的方式03源码验证04总结

前言

用了多年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,这就和之前的想当然有出入。于是只好查看源码

02源码查看

源码查看有2种方式,本文的示例是springboot项目

01从main方法直接调试断点

从图可以看出如果是以扫描注解注入形式,其beanName的生成规则是由

org.springframework.context.annotation.AnnotationBeanNameGenerator#generateBeanName

决定。

ps: 这种直接从main启动类调试起,比较适用于时间比较多,或者排查毫无头绪

02带着问题查看,靠猜加验证的方式

利用idea的find Usage查找引用,比如ABService的注解@service,我们可以直接查看哪个引用到@Service,再猜测下beanName的生成规则

通过猜,我们基本上就可以定位出比较符合我们需求的方法

03源码验证

从上面的分析,我们可以知道如果是扫描bean注解注入的方式,其生成beanName规则,是在

org.springframework.context.annotation.AnnotationBeanNameGenerator

其生成规则代码如下

@Override

public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {

if (definition instanceof AnnotatedBeanDefinition) {

String beanName = determineBeanNameFromAhttp://nnotation((AnnotatedBeanDefinition) definition);

if (StringUtils.hasText(beanName)) {

// Explicit bean name foundpJNOtz.

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.

*

* 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.

*/

04总结

通过扫描bean注解注入IOC时,如果不指定bean名称的默认规则是类名的首字母小写,如果类名前两个或以上个字母都是大写,那么bean名称与类名一样。

其实这个细节可能懂的都懂,本文的彩蛋主要是分享一下平时查看源码的一点心得吧,哈哈

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:提供免费数据的api接口(免费API数据调用)
下一篇:淘宝免费api数据接口(淘宝订单接口api接口)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~