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),这样可以解耦并方便扩展。

posted @ 2025-09-26 23:47  AlphaGeek  阅读(1)  评论(0)    收藏  举报