Spring Boot 中注入 Bean 的常见方式如下,每种方式适用于不同的场景:
1. @Autowired
注解(字段注入)
- 说明:按类型自动装配,可作用于构造器、Setter 方法、字段或普通方法。
- 场景:大多数情况下的依赖注入。
- 示例:
java
- 体验AI代码助手
- 代码解读
- 复制代码
@Service
public class MyService {
@Autowired // 字段注入
private MyRepository repository;
}
2. 构造器注入(推荐)
- 说明:通过构造器注入依赖,Spring 4.3+ 中若类只有单个构造器,可省略
@Autowired
。 - 优势:强制依赖不可变,避免空指针。
- 示例:
java
- 体验AI代码助手
- 代码解读
- 复制代码
@Service
public class MyService {
private final MyRepository repository;
public MyService(MyRepository repository) { // 自动注入
this.repository = repository;
}
}
3. @Resource
注解
- 说明:按名称注入(JSR-250 规范),默认按字段名或方法名匹配 Bean。
- 场景:需明确指定 Bean 名称时。
- 示例:
java
- 体验AI代码助手
- 代码解读
- 复制代码
@Service
public class MyService {
@Resource(name = "myRepositoryImpl")
private MyRepository repository;
}
4. @Bean
方法(Java 配置类)
- 说明:在
@Configuration
类中定义@Bean
方法,返回对象由 Spring 管理。 - 场景:配置第三方库组件或复杂 Bean。
- 示例:
java
- 体验AI代码助手
- 代码解读
- 复制代码
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
return new HikariDataSource();
}
}
5. @Value
注解
- 说明:注入配置文件属性或 SpEL 表达式。
- 场景:注入简单值(如字符串、数字)或动态表达式。
- 示例:
java
- 体验AI代码助手
- 代码解读
- 复制代码
@Component
public class MyComponent {
@Value("${app.timeout:1000}") // 注入配置,默认值 1000
private int timeout;
}
6. XML 配置(传统方式)
- 说明:通过 XML 定义 Bean,需配合
@ImportResource
导入。 - 场景:遗留项目迁移或混合配置。
- 示例:
xml
- 体验AI代码助手
- 代码解读
- 复制代码
<!-- applicationContext.xml -->
<bean id="myBean" class="com.example.MyBean"/>
java
- 体验AI代码助手
- 代码解读
- 复制代码
@SpringBootApplication
@ImportResource("classpath:applicationContext.xml")
public class App { ... }
7. ApplicationContextAware
手动获取
- 说明:实现接口获取
ApplicationContext
,直接调用getBean()
。 - 场景:非 Spring 管理类中动态获取 Bean(不推荐常规使用)。
- 示例:
java
- 体验AI代码助手
- 代码解读
- 复制代码
@Component
public class MyBean implements ApplicationContextAware {
private ApplicationContext context;
@Override
public void setApplicationContext(ApplicationContext context) {
this.context = context;
}
public void useBean() {
MyService service = context.getBean(MyService.class);
}
}
8. JSR-330 的 @Inject
注解
- 说明:与
@Autowired
功能类似,需引入javax.inject
依赖。 - 示例:
java
- 体验AI代码助手
- 代码解读
- 复制代码
@Service
public class MyService {
@Inject
private MyRepository repository;
}
9. Setter 方法注入
- 说明:通过
@Autowired
注解标记在 Setter 方法上,Spring 会调用该方法注入依赖。 - 场景:
- 可选依赖:依赖不是必须的(例如有默认实现)。
- 动态重新注入:需要运行时更换依赖(较少见)。
- 示例:
java
- 体验AI代码助手
- 代码解读
- 复制代码
@Service
public class MyService {
private MyRepository repository;
@Autowired // Setter 方法注入
public void setRepository(MyRepository repository) {
this.repository = repository;
}
}
Setter 方法注入是 Spring 中另一种常见的依赖注入方式,尤其是在早期 Spring 版本中广泛使用。可能因为它在现代 Spring Boot 项目中逐渐被构造器注入取代(官方推荐)
为什么 Setter 注入逐渐被淡化?
- 不可变性与安全性
- 构造器注入能确保依赖在对象创建时就被初始化,避免
NullPointerException
。 - Setter 注入允许依赖在对象创建后修改(除非代码刻意限制),可能破坏不变性。
- 代码简洁性
- 构造器注入无需写 Setter 方法,减少样板代码(尤其配合 Lombok
@RequiredArgsConstructor
)。
- 框架演进
- Spring 官方自 4.x 起推荐构造器注入,明确依赖的强制性,提升组件可靠性。
Setter 注入的合理使用场景
- 可选依赖:依赖可能为
null
,且有默认处理逻辑。
java
- 体验AI代码助手
- 代码解读
- 复制代码
@Autowired(required = false) // 依赖不存在时不报错
public void setOptionalDependency(OptionalDependency dep) {
this.dep = dep != null ? dep : new DefaultDependency();
}
- 循环依赖:某些复杂场景下,Setter 注入可配合
@Lazy
解决循环依赖(但设计上应尽量避免循环依赖)。
9. 构造器注入最新方式
通过类的构造器注入依赖,结合 Lombok 的 @RequiredArgsConstructor
可自动生成构造器。
java
体验AI代码助手
代码解读
复制代码
@Service
@RequiredArgsConstructor // Lombok 自动生成构造器(注入方式)
public class UserService {
private final UserRepository userRepository; // 依赖
}
为什么 Lombok 属于依赖注入?
- Lombok 的作用:通过
@RequiredArgsConstructor
自动生成包含final
字段的构造器,减少了手动编写构造器的代码量。 - Spring 的配合:当类被声明为 Bean(如
@Service
)后,Spring 会自动通过生成的构造器完成依赖注入。 - 本质:Lombok 只是简化了依赖注入的代码编写,不参与 Bean 的声明过程。
- 优先使用构造器注入:强制依赖、不可变性、代码简洁性。
- 按需使用 Setter 注入:可选依赖或特殊场景。
- 避免滥用字段注入:虽然方便,但隐藏依赖关系,不利于测试和维护。
总结
- 推荐方式:构造器注入(不可变依赖) +
@Autowired
(可选依赖)。 - 避免使用:字段注入(不利于测试)和
ApplicationContextAware
(破坏控制反转)。 - 按需选择:
@Resource
(按名称注入)、@Value
(配置值)或@Bean
(复杂配置)。 - Lombok 属于依赖注入的优化工具
- 最佳实践:使用
@Component
等注解声明 Bean + 构造器注入(配合 Lombok 简化代码)。