@Autowired 注解针对父类注入时加载方式分析
问题:1.springBoot 类 BService 继承 类 AService ,在写CLassA单元测试的时候如果写成@Autowiredprivate AService service;或者写成:@Autowiredprivate AService wefsd; //一个乱七八糟的字符组成启动容器的时候会报错,显示:NoUniqueBeanDefinitionException , X.X.
问题:
1.springBoot 类 BService 继承 类 AService ,在写CLassA单元测试的时候
如果写成
@Autowired
private AService service;
或者写成:
@Autowired
private AService wefsd; //一个乱七八糟的字符组成
启动容器的时候会报错,显示:
NoUniqueBeanDefinitionException , X.X.X.XAService这个bean,发现了两个一个是 aService,一个是bService,
分析:
@Autowired 默认按照类型加载,如果存在多个类型相同的bean,类似这种父子关系,导致无法确认唯一结果的时候,会接着按照名称查找,我本来以为这个名称指的是bean的默认名字(目前案例中没有显示指定),但是这个默认名字和我自定的变量名有什么关系呢,我的理解是 默认bean名字是 类名首字母小写(aService),我恰好定义的变量名称(service,wefsd,)不相同,此时报错,推测原因是 容器平台把这个变量名称定义为bean名称,发现按照名称也找不到,所以报错,如果我写成下面的这个:
@Autowired
private AService aService;
就不会报错了,这个时候,bean名称默认就是变量名称。。。待定
//=============================第二次测试如下 ==========================================
父子类如下:
@Service
@Slf4j
public class ParentService {
void parentPrint() {
log.info("this is ParentService parentPrint function");
}
}
@Service
@Slf4j
public class ChildService extends ParentService {
void childPrint() {
log.info("this is ChildService childPrint function");
}
}
子类测试1 :private ChildService childService;
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class ChildServiceTest1 {
@Autowired
private ChildService childService;
@Test
public void test(){
childService.childPrint();
}
}
结果显示正常
子类测试2:private ChildService sssss;
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class ChildServiceTest2 {
@Autowired
private ChildService sssss;
@Test
public void test(){
sssss.childPrint();
}
}
结果显示正常
父类测试1 :private ParentService parentService;
@ExtendWith(SpringExtension.class)
@SpringBootTest
public class ParentServiceTest1 {
@Autowired
private ParentService parentService;
@Test
public void test(){
parentService.parentPrint();
}
}
结果显示正常
父类测试2 : private ParentService ssss;
ExtendWith(SpringExtension.class)
@SpringBootTest
@Slf4j
public class ParentServiceTest2 {
@Autowired
private ParentService ssss;
@Test
public void test(){
ssss.parentPrint();
}
}
结果异常
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo.test1.service.ParentServiceTest2': Unsatisfied dependency expressed through field 'ssss'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.test1.service.ParentService' available: expected single matching bean but found 2: childService,parentService
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:643)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:130)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399)
日志里面显示:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.example.demo.test1.service.ParentServiceTest2': Unsatisfied dependency expressed through field 'ssss'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.example.demo.test1.service.ParentService' available: expected single matching bean but found 2: childService,parentService
首先,我们知道 @Autowired 默认按照类型装配,如果类型不能唯一确定那么就按照名称装配
根据 上面四个实验可以得出结论:
1. 子类注入的时候是按照类型选择的,否则 子类测试2实验应该就会失败,也就是说在注入子类的时候,根据类型就可以唯一确认,子类是特殊的父类,这个应该没问题;
2.父类是按照名称装配的,否则父类测试2 不应该报错,相对来说,父类较为宽泛,所以注入父类会发现有两个bean,那么这个时候就会开始按照名称查找,这个名称spring会把变量名作为bean名称来查询,这也就是父类测试2失败以及父类测试1成功的的原因了。
3.补充:@Resource 按照名称查找,这个名称就是变量名称。
更多推荐
所有评论(0)