
Spring中构造器注入和Setter注入:深入理解
在Spring框架中,依赖注入(Dependency Injection, DI)是一个核心概念,用于将对象的依赖关系从代码中分离出来,通过外部容器(如Spring容器)来管理这些依赖关系。Spring提供了多种依赖注入方式,其中最常用的两种是构造器注入(Constructor Injection)和Setter方法注入(Setter Injection)。
1. 前置知识:Spring中的依赖注入
1.1 什么是依赖注入?
依赖注入是一种设计模式,用于将对象的依赖关系从代码中分离出来,通过外部容器(如Spring容器)来管理这些依赖关系。依赖注入使得代码更加松耦合,易于测试和维护。
1.2 Spring中的依赖注入方式
Spring框架提供了多种依赖注入方式,包括:
构造器注入(Constructor Injection)
Setter方法注入(Setter Injection)
字段注入(Field Injection)
2. 构造器注入(Constructor Injection)
构造器注入是最推荐的依赖注入方式,因为它确保了对象在创建时就已经拥有了所有必要的依赖。构造器注入通过构造器参数来注入依赖。
2.1 基本用法
以下是一个简单的示例,展示了如何使用构造器注入。
@Service
public class MyService {
private final MyRepository myRepository;
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
public void doSomething() {
myRepository.doSomething();
}
}
在这个例子中,MyService类通过构造器注入的方式使用了MyRepository Bean。Spring容器会自动将MyRepository Bean注入到MyService中。
注意:
Spring 默认支持 基于构造函数的依赖注入,其执行逻辑为:
单构造函数场景:若类中仅存在一个构造函数(无论是否有参数),Spring 会自动选择该构造函数实例化 Bean,并尝试通过容器中已存在的 Bean 自动注入参数。(如果没有显式地定义任何构造方法,编译器会自动为我们生成一个无参构造方法。则使用默认的无参构造函数)
多构造函数场景:若存在多个构造函数,需通过
@Autowired
显式指定要使用的构造函数。
在用户提供的代码中,ForumCoreAutoConfig
仅有一个带参数的构造函数,因此 Spring 会直接使用它完成实例化。
2.2 优点
不可变性:构造器注入使得依赖关系不可变,从而避免了在运行时修改依赖关系的可能性。
线程安全:由于依赖关系在对象创建时就已经确定,因此构造器注入是线程安全的。
易于测试:构造器注入使得单元测试更加简单,因为你可以轻松地为依赖关系提供模拟对象。
2.3 多参数构造器
如果需要注入多个依赖,可以使用多参数构造器。
@Service
public class MyService {
private final MyRepository myRepository;
private final MyConfig myConfig;
public MyService(MyRepository myRepository, MyConfig myConfig) {
this.myRepository = myRepository;
this.myConfig = myConfig;
}
public void doSomething() {
myRepository.doSomething();
myConfig.doSomething();
}
}
在这个例子中,MyService类通过多参数构造器注入了MyRepository和MyConfig Bean。
3. Setter方法注入(Setter Injection)
Setter方法注入通过Setter方法来注入依赖。这种方式允许在对象创建后动态地更改依赖。
3.1 基本用法
以下是一个简单的示例,展示了如何使用Setter方法注入。
@Service
public class MyService {
private MyRepository myRepository;
@Autowired
public void setMyRepository(MyRepository myRepository) {
this.myRepository = myRepository;
}
public void doSomething() {
myRepository.doSomething();
}
}
在这个例子中,MyService类通过Setter方法注入的方式使用了MyRepository Bean。Spring容器会自动调用setMyRepository方法,将MyRepository Bean注入到MyService中。
3.2 优点
灵活性:Setter方法注入允许在对象创建后动态地更改依赖关系,从而提供了更大的灵活性。
可选依赖:Setter方法注入可以用于注入可选依赖,即依赖关系可以为空。
3.3 多参数Setter方法
如果需要注入多个依赖,可以使用多个Setter方法。
@Service
public class MyService {
private MyRepository myRepository;
private MyConfig myConfig;
@Autowired
public void setMyRepository(MyRepository myRepository) {
this.myRepository = myRepository;
}
@Autowired
public void setMyConfig(MyConfig myConfig) {
this.myConfig = myConfig;
}
public void doSomething() {
myRepository.doSomething();
myConfig.doSomething();
}
}
在这个例子中,MyService类通过多个Setter方法注入了MyRepository和MyConfig Bean。
4. 构造器注入与Setter方法注入的比较
构造器注入和Setter方法注入各有优缺点,适用于不同的场景。
4.1 构造器注入的优点
不可变性:构造器注入使得依赖关系不可变,从而避免了在运行时修改依赖关系的可能性。
线程安全:由于依赖关系在对象创建时就已经确定,因此构造器注入是线程安全的。
易于测试:构造器注入使得单元测试更加简单,因为你可以轻松地为依赖关系提供模拟对象。
4.2 构造器注入的缺点
复杂性:如果需要注入多个依赖,构造器参数可能会变得复杂,从而增加代码的复杂性。
可选依赖:构造器注入不支持可选依赖,即依赖关系必须存在。(不然无法构造)
构造器注入通常推荐用于强制依赖,因为它能保证依赖项在对象创建时就被设置,避免NullPointerException。而Setter注入适合可选依赖,或者需要后期重新配置的情况。
4.3 Setter方法注入的优点
灵活性:Setter方法注入允许在对象创建后动态地更改依赖关系,从而提供了更大的灵活性。
可选依赖:Setter方法注入可以用于注入可选依赖,即依赖关系可以为空。
4.4 Setter方法注入的缺点
可变性:Setter方法注入使得依赖关系可变,从而增加了在运行时修改依赖关系的可能性。
线程不安全:由于依赖关系在对象创建后可以更改,因此Setter方法注入不是线程安全的。
难以测试:Setter方法注入使得单元测试更加复杂,因为你需要确保在测试时正确设置了依赖关系。
5. 实际应用场景
构造器注入和Setter方法注入在实际项目中有广泛的应用场景,特别是在需要依赖注入的场景中。
5.1 服务层注入
在服务层中,通常需要注入多个依赖的Bean,如存储库、配置等。
@Service
public class MyService {
private final MyRepository myRepository;
private final MyConfig myConfig;
public MyService(MyRepository myRepository, MyConfig myConfig) {
this.myRepository = myRepository;
this.myConfig = myConfig;
}
public void doSomething() {
myRepository.doSomething();
myConfig.doSomething();
}
}
在这个例子中,MyService类通过构造器注入的方式注入了MyRepository和MyConfig Bean。
5.2 控制器层注入
在控制器层中,通常需要注入服务层的Bean。
@Controller
public class MyController {
private final MyService myService;
public MyController(MyService myService) {
this.myService = myService;
}
@GetMapping("/doSomething")
public String doSomething() {
myService.doSomething();
return "success";
}
}
在这个例子中,MyController类通过构造器注入的方式注入了MyService Bean。
5.3 配置类注入
在配置类中,通常需要注入其他配置类或Bean。
@Configuration
public class AppConfig {
private MyConfig myConfig;
@Autowired
public void setMyConfig(MyConfig myConfig) {
this.myConfig = myConfig;
}
@Bean
public MyService myService() {
return new MyService(myConfig);
}
}
在这个例子中,AppConfig类通过Setter方法注入的方式注入了MyConfig Bean,并在myService Bean的定义中使用了myConfig。
6. 总结
构造器注入和Setter方法注入是Spring框架中常用的依赖注入方式。构造器注入通过构造器参数来注入依赖,确保了对象在创建时就已经拥有了所有必要的依赖,从而提供了不可变性、线程安全性和易于测试的优点。Setter方法注入通过Setter方法来注入依赖,允许在对象创建后动态地更改依赖关系,从而提供了灵活性和可选依赖的优点。在实际项目中,开发者可以根据具体需求选择合适的注入方式。
- 感谢你赐予我前进的力量