Autowired自动装配

#注解 #Spring #自动装配

@Autowired 的自动装配模式

@Autowired 默认是 按类型 (byType) 自动注入的。

按类型注入

按类型注入指的是:当 Spring 发现当前字段有 @Autowired 的标注之后,会去查看其字段类型,然后去寻找已注册的实现了当前字段类型的 Bean 然后初始化注入。

@Autowired
private UserService userService;
// 当前字段类型为 UserService

// UserService.java
public interface UserService { ... }

// UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService { ... }

在上面例子中,已注册的实现 UserService 的 Bean 是 UserServiceImpl,Spring 会把这个 Bean 实例化注入到 userService 中。


当有多个同类型 Bean 时会怎样,如何解决?

在上面的例子中如果我们同时实现了多个 UserService 的话会怎样?

@Autowired
private UserService userService;

// UserService.java
public interface UserService { ... }

// UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService { ... }

// UserServiceImpl2.java
@Service
public class UserServiceImpl2 implements UserService { ... }

这种情况会抛出 NoUniqueBeanDefinitionException 错误。

解决方案:@Qualifier 显式指定

可以使用 @Qualifier 注解指定具体的 Bean 名称,从而在多个同类型 Bean 中精确选择一个进行注入。

@Qualifier("userServiceImpl") // 注意:默认 bean 名称为类名首字母小写
@Autowired
private UserService userService;

@Service 注解默认生成的 Bean 名称是类名的首字母小写(如 UserServiceImpl → userServiceImpl)

解决方案:@Primary 标记首选

@Service
@Primary
public class UserServiceImpl implements UserService { ... }

标记了 @Primary 的 Bean 会在多个候选 Bean 中被优先选择。


@Autowired 的注入位置

1. 字段注入

@Autowired
private UserService userService;
  • 简洁直接
  • 不支持 final 字段
  • 不利于单元测试

2. Setter 注入

private UserService userService;

@Autowired
public void setUserService(UserService userService) {
    this.userService = userService;
}
  • 可选依赖
  • 不支持 final 字段

3. 构造器注入(推荐)

private final UserService userService;

@Autowired
public UserController(UserService userService) {
    this.userService = userService;
}

从 Spring 4.3 开始,如果类只有一个构造器,@Autowired 可以省略。

优点:

  • 支持 final 字段,保证不可变性
  • 依赖关系清晰,便于理解
  • 便于单元测试(可以直接 new 对象)
  • 配合 Lombok 的 @RequiredArgsConstructor 更简洁