修正
引用处修正
@Autowired @Qualifier("cassandraDataService") DataService dataService;
定义处显式指定Bean名字,我们可以保持引用代码不变,而通过显式指明CassandraDataService 的Bean名称为CassandraDataService来纠正这个问题。
@Repository("CassandraDataService") @Slf4j public class CassandraDataService implements DataService { //省略实现 }
如果你不太了解源码,不想纠结于首字母到底是大写还是小写,建议第二种方法
引用内部类的Bean遗忘类名
这就能搞定所有Bean显式引用不出 bug 吗?
沿用上面案例,稍微再添加点别的需求,例如我们需要定义一个内部类来实现一种新的DataService,代码如下:
public class StudentController { @Repository public static class InnerClassDataService implements DataService{ @Override public void deleteStudent(int id) { //空实现 } } // ... }
这时一般都用下面的方式直接去显式引用这个Bean:
@Autowired @Qualifier("innerClassDataService") DataService innerClassDataService;
那直接采用首字母小写,这样就万无一失了吗?
仍报错“找不到Bean”,why?
答疑
现在问题是“如何引用内部类的Bean”。
在AnnotationBeanNameGenerator#buildDefaultBeanName,只关注了首字母是否小写,而在最后变换首字母前,有这么一行处理 class 名称的:
我们可以看下它的实现:
ClassUtils#getShortName
假设是个内部类,例如下面的类名:
com.javaedge.StudentController.InnerClassDataService
经过该方法处理后,得到名称:
StudentController.InnerClassDataService
最后经Introspector.decapitalize
首字母变换,得到Bean名称:
studentController.InnerClassDataService
所以直接使用 innerClassDataService 找不到想要的Bean。
修正
@Autowired @Qualifier("studentController.InnerClassDataService") DataService innerClassDataService;
总结
像第一个案例,同种类型的实现,可能不是同时出现在自己的项目代码中,而是有部分实现出现在依赖的类库。看来研究源码的确能让我们少写几个 bug!