@Autowired和 @Qualifier 注解
错误如下:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type ‘com.xxx.xxx.xxx.callable.ITaskRunable’ available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=oAuthShopAccessTokenTask)}
@Autowired注解和@Qualifier注解 通常和 @Resource 注解一同比较。那我们再来回顾一下。
@Autowired 是基于Type进行注入的,即基于Bean的类型进行注入的。如果相同的Bean类型存在两个,比如 按接口类型进入注入,但是存在多个实现类,则会出现异常。此时我们可以使用@Qualifier注解进行配合使用。
@Qualifier就是当使用Autowired注解进行注入时,但是此时又存在多个相同类型的Bean的时候,就可以通过@Qualifier注解进行按名字指定。
@Resource 注解就当于上面两个注解组合使用的效果。@Resource默认是按照执行的名字进行注入的。如果遇到相同的名字则会按类型进行注入,最后如果选择不到一个唯一的,则会抛出异常。
以上@Autowired注解,@Qualifier注解,@Resource注解的作用我们基本都能知道。但是在实际操作中常常会遇到一些其他问题。多个Bean的异常可以好排查一点,但是无法注入的情况,就比较难搞。今天在开发过程中就排查了好久。
如果遇到Spring无法注入Bean的情况,可以从以下几个方向入手排查:
- 是否需要注入的类没有被扫描到。
- 如果是Spring项目,看配置文件中的
<context: componentScan>
注解的扫描范围,是否扫描到了。 - 如果是SpringBoot项目,默认扫描的是
@SpringBootApplication
类所在的包及其子包,所以看自己的组件是否满足条件。
- 按名称注入,名称是否一致。(遇到的坑)
- 普通首字母大写的类,如StudentService,使用@Service等加入到Spring容器中,其名字为类型的首字母小写形式。
- 如果是两个或两个以上大写字母开头的类,如 OAuthTaskService 类,使用@Service 等注解加入到Spring容器后,其名字是其
类名
.
我们来看一下源码, 类 AnnotationBeanNameGenerator
我们查看一下 buildDefaultBeanName 方法,调用了 Introspector.decapitalize(String name)
可以看到 if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0)))
这一行,就是 第一个和第二个字母是大写字母,则直接访问原类名。
否则把首字母变为小写,再返回。