Sping bean 的默认名称
创始人
2024-01-21 06:49:50
0

先来看一个例子,我定义一个Service , IDataService 它有2个实现类:OracleServiceSQLService
代码如下:

public interface IDataService {void showMsg(String msg) ;
}
@Repository
public class OracleService implements IDataService{@Overridepublic void showMsg(String msg) {System.out.println("oracle >>> " + msg);}
}
@Repository
public class SQLService implements IDataService{@Overridepublic void showMsg(String msg) {System.out.println("SQL >>>> " +msg);}
}

测试调用代码如下:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("classpath:demo_sacn.xml")
public class TestService {@AutowiredIDataService dataService;@Testpublic void dd() {dataService.showMsg("oracle service");}}

运行,结果报错了,如下:

No qualifying bean of type 'com.example.demo.service.IDataService' available: expected single matching bean but found 2: oracleService,sqlService

为啥会报错,原因很简单,我这里有2个IDataService的实现类。那么如何解决呢?
通用的解法是加上限定符的注解 @Qualifier,如下:

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration("classpath:demo_sacn.xml")
public class TestService {@Qualifier("oracleService")@AutowiredIDataService dataService;@Testpublic void dd() {dataService.showMsg("oracle service");}}

这样就能正常执行。@Qualifier("oracleService") 中的 oracleService 就是 Bean 的默认名称。

这里我们很容易得出一个结论:对于 Bean 的名字,如果没有显式指明,就应该是类名,不过首字母应该小写。但是这个轻松得出的结论成立么?

我们进行一个测试,修改@Qualifier("oracleService")中的值为 @Qualifier("sQLService"),结果发现报错了。

No qualifying bean of type 'com.example.demo.service.IDataService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=sQLService), @org.springframework.beans.factory.annotation.Autowired(required=true)}

满怀信心运行完上面的程序,依然会出现之前的错误,而如果改成 SQLiteDataService,则运行通过了。这和之前的结论又矛盾了。所以,显式引用 Bean 时,首字母到底是大写还是小写呢

看案例的话,当我们启动基于 Spring Boot 的应用程序时,会自动扫描我们的 Package,以找出直接或间接标记了 @Component 的 Bean 的定义(即 BeanDefinition)。例如 OracleServiceSQLService 都被标记了 @Repository,而 Repository 本身被 @Component 标记,所以它们都是间接标记了 @Component

一旦找出这些 Bean 的信息,就可以生成这些 Bean 的名字,然后组合成一个个 BeanDefinitionHolder 返回给上层。

基本匹配我们前面描述的过程,其中方法调用 BeanNameGenerator#generateBeanName 即用来产生 Bean 的名字,它有两种实现方式。因为 DataService 的实现都是使用注解标记的,所以 Bean 名称的生成逻辑最终调用的其实是 AnnotationBeanNameGenerator#generateBeanName 这种实现方式,我们可以看下它的具体实现,代码如下:

 public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {if (definition instanceof AnnotatedBeanDefinition) {String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);if (StringUtils.hasText(beanName)) {return beanName;}}// Fallback: generate a unique default bean name.                return buildDefaultBeanName(definition, registry);}

大体流程只有两步:看 Bean 有没有显式指明名称,如果有则用显式名称,如果没有则产生一个默认名称。很明显,在我们的案例中,是没有给 Bean 指定名字的,所以产生的 Bean 的名称就是生成的默认名称,查看默认名的产生方法 buildDefaultBeanName,其实现如下:

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

首先,获取一个简短的 ClassName,然后调用 Introspector#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);}

到这,我们很轻松地明白了前面两个问题出现的原因:如果一个类名是以两个大写字母开头的,则就是类名,其它情况下默认首字母变成小写。结合我们之前的案例,SQLService 的 Bean,其名称应该就是类名本身,而 OracleService 的 Bean 名称则变成了首字母小写(oracleService)。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...