詳解關於spring bean名稱命名的那些事
前言
用瞭多年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 = 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. */
04總結
通過掃描bean註解註入IOC時,如果不指定bean名稱的默認規則是類名的首字母小寫,如果類名前兩個或以上個字母都是大寫,那麼bean名稱與類名一樣。
其實這個細節可能懂的都懂,本文的彩蛋主要是分享一下平時查看源碼的一點心得吧,哈哈
到此這篇關於spring bean名稱命名的文章就介紹到這瞭,更多相關spring bean名稱命名內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Spring五大類註解讀取存儲Bean對象的方法
- 向Spring IOC 容器動態註冊bean實現方式
- Spring Bean的包掃描的實現方法
- Spring源碼解析容器初始化構造方法
- 如何動態替換Spring容器中的Bean