一、@Autowired
@Autowired 默认按照类型 (byType) 注入,如果按照类型注入时,匹配到多个结果,就会按照名称 (byName) 注入(ps:所以 @Autowired 也可以按照名称注入呦)。
当 @Autowired 通过 byName 进行注入时,会获取属性的 name 进行匹配,例如:
@Autowired
private UserService userService;
获取到的名字就是 userService,将获取到的属性名称 userService 与前面通过类型匹配到多个 bean 进行 name 比对,如果匹配出唯一结果,则结束。如果还是匹配出多个结果,则抛异常 NoUniqueBeanDefinitionException。
二、@Resource
@Resource 默认按照 (byName) 进行属性注入,如果通过 name 无法找到相应的 bean 实例,接着就通过 byType 进行匹配。按照 byType 匹配的逻辑和 @Autowired 匹配走的是同一套逻辑,所以 @Resource 的匹配逻辑为 byName -> byType -> byName。
三、结论验证
1、定义一个用户服务接口
public interface UserService {
void getName(String name);
}
2、定义用户服务接口的两个实现类 UserServiceImpl1 和 UserServiceImpl2
@Service
public class UserServiceImpl1 implements UserService {
@Override
public void getName(String name{
System.out.println("UserServiceImpl1");
}
}
@Service
public class UserServiceImpl2 implements UserService {
@Override
public void getName(String name) {
System.out.println("UserServiceImpl2");
}
}
3、定义一个 Controller
@RestController
public class UserController {
@Autowired
private UserService userService;
public void getName(){
userService.getName();
}
}
4、验证 @Autowired 的注入
- 测试1:当 UserServiceImpl1 和 UserServiceImpl2 同时存在,在 UserController 采用以下注入方式,必然会报错,因为 @Autowired 是根据 类型(byType)注入的,因为两个实现类 bean 都实现了 UserService ,那肯定找到两个了,结局不唯一,只能按照 byName 注入,此时的 name 为“userService”(实际两个业务实现类我们用 @Service 丢到 Spring 容器里面默认名字是首字母小写 userServiceImpl1、userServiceImpl2),根本没有 “userService” 这个东东,结果无法唯一确定,只能抛出异常。(ps:byType 和 byName 都无法注入)
@Autowired
private UserService userService;
- 测试2:当 UserServiceImpl1 和 UserServiceImpl2 同时存在,此时相比测试1 的区别是 “userService” 改为了 “UserServiceImpl1”,这次就能正常执行,并且输出结果为 “userServiceImpl1”。(ps:byType 查找到多个示例,通过 byName 注入)
@Autowired
private UserService userServiceImpl1;
- 测试3:当 UserServiceImpl1 和 UserServiceImpl2 同时存在,但此时我就想使用测试1中的 “userService”该怎么办呢?这时候我们可以采用另一个注解 @Qualifier 来指定注入的名称,此时也就正确输出结果 “UserServiceImpl1”。(ps:byType 查找到多个示例,通过 byName 注入)
@Autowired
@Qualifier("userServiceImpl1")
private UserService userService;
- 测试4:当只有一个接口实现类 UserServiceImpl1,毫无疑问,按照类型就行注入,打印的结果也是 “UserServiceImpl1”,这也是我们平时见过的最多的实现。(ps:byType 注入)
5、验证 @Resource 的注入
- 测试1:当 UserServiceImpl1 和 UserServiceImpl2 同时存在,在 UserController 采用以下注入方式,必然会报错。因为 @Resource 默认是根据 名字(byName)注入的,此时的 name 是 “userService”,发现根本没有这个 userService ,因为我们注入到 bean 容器里面是这两个玩意(@Service),而且咋们使用 @Service 注入这俩玩意没有起别名,那么就是默认 首字母变小写 当做注入的 bean 名字(“userServiceImpl1” 和 “userServiceImpl2”),所以没有匹配结果。那么就会根据 type 类型(UserService)去 Spring 容器里面找找,有没有这种类型的 bean,结果发现了两个类型都是 UserService 的两个倒霉孩子 userServiceImpl1 和 userServiceImpl2,所以就报错了。(ps:byName 和 byType 都无法注入)
@Resource
private UserService userService;
- 测试2:当 UserServiceImpl1 和 UserServiceImpl2 同时存在,此时相比测试1的区别是 “userService” 改为了 “UserServiceImpl1”,这次就能正确执行,并且输出结果为 “UserServiceImpl1”。(ps:通过 byName 匹配到了唯一的 bean 实例)
@Resource
private UserService userServiceImpl1;
- 测试3:当 UserServiceImpl1 和 UserServiceImpl2 同时存在,但此时我就想使用测试1中的 “userService”该怎么办呢?这时候我们可以在 @Resource 注解中指定注入的名称,此时也能正确输出结果 “userServiceImpl1”。(ps:通过 byName 匹配到了唯一的 bean 实例)
@Resource(name = "userServiceImpl1")
private UserService userService;
- 测试4:当只有一个接口实现类 UserServiceImpl1,采用以下注入方式,此时是按照 byType 注入,打印的结果也是 “userServiceImpl1”。(ps:byType 注入)。
@Resource
private UserService userService;