Java中,Spring Boot 中 @Autowired 注入【接口】与【实现类】的区别,细节详解!
Spring Boot 中 @Autowired 注入接口与实现类的区别
疑问说明
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
UserService userService; // 这里写接口 IUserService userService,或者 UserService userService 都能够通过编译吗?
@PostMapping
public ResponseMessage<User> addUser(@Validated @RequestBody UserDto userDto) {
User user = userService.addUser(userDto);
return ResponseMessage.success(user);
}
@GetMapping("/{userId}")
public ResponseMessage<User> getUserById(@Validated @PathVariable Integer userId) {
User user = userService.getUser(userId);
return ResponseMessage.success(user);
}
@PutMapping
public ResponseMessage<User> updateUser(@Validated @RequestBody UserDto userDto) {
User user = userService.updateUser(userDto);
return ResponseMessage.success(user);
}
@DeleteMapping("/{userId}")
public ResponseMessage<User> deleteUser(@Validated @PathVariable Integer userId) {
userService.deleteUser(userId);
return ResponseMessage.success();
}
}
回答
1. 写 UserService userService
- 能编译通过:Spring 会扫描到
@Service注解的UserService类,把它注册为 Bean,然后通过类型匹配自动注入。 - 相当于直接依赖具体实现类。
- 缺点:强耦合,如果以后有多个实现类,要替换就需要改 Controller 里的代码。
2. 写 IUserService userService
- 也能编译通过,前提是
UserService实现了IUserService接口。 - Spring 会找到实现了
IUserService的那个 Bean(即UserService),注入到IUserService变量中。 - 优点:低耦合,推荐使用。
3. 注意点
如果接口有多个实现,Spring 会报错:NoUniqueBeanDefinitionException。这时需要:
- 用
@Qualifier("beanName")指定 Bean; - 或者在某个实现类上加
@Primary。
多实现类示例
1. 定义接口
package com.xushu.springboot_xushu.service;
public interface IUserService {
String getUserInfo();
}
2. 两个实现类
package com.xushu.springboot_xushu.service.impl;
import com.xushu.springboot_xushu.service.IUserService;
import org.springframework.stereotype.Service;
@Service("userServiceV1")
public class UserServiceV1 implements IUserService {
@Override
public String getUserInfo() {
return "我是 UserService V1 实现";
}
}
package com.xushu.springboot_xushu.service.impl;
import com.xushu.springboot_xushu.service.IUserService;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
@Service("userServiceV2")
@Primary // 当有多个实现时,默认优先注入这个
public class UserServiceV2 implements IUserService {
@Override
public String getUserInfo() {
return "我是 UserService V2 实现(默认)";
}
}
3. Controller 使用注入
方式一:默认注入(用 @Primary 的实现)
package com.xushu.springboot_xushu.controller;
import com.xushu.springboot_xushu.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
@Autowired
private IUserService userService; // 会注入 UserServiceV2,因为它被标记了 @Primary
@GetMapping("/user/default")
public String getDefaultUserInfo() {
return userService.getUserInfo();
}
}
方式二:指定实现(用 @Qualifier)
package com.xushu.springboot_xushu.controller;
import com.xushu.springboot_xushu.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserQualifierController {
@Autowired
@Qualifier("userServiceV1") // 指定要注入的 Bean 名称
private IUserService userService;
@GetMapping("/user/v1")
public String getUserInfoV1() {
return userService.getUserInfo();
}
}
4. 效果
-
访问
http://localhost:8080/user/default
👉 返回:我是 UserService V2 实现(默认) -
访问
http://localhost:8080/user/v1
👉 返回:我是 UserService V1 实现
✅ 总结:推荐在 Controller 层依赖接口(IUserService),这样可以解耦并方便扩展。

浙公网安备 33010602011771号