问:说说Spring中构造函数注入和Setter注入的区别?
在Spring框架中,构造函数注入和setter注入是两种常见的依赖注入方式。它们的主要区别在于依赖对象的注入时机和注入方式。
构造函数注入
构造函数注入是通过类的构造函数来注入依赖对象的。在Spring创建bean实例时,就会通过构造函数将依赖对象传递进去。这种方式确保了依赖对象在bean实例化时就已经被注入,因此可以保证bean在使用时所有依赖都已经准备好。
代码示例:
// 定义依赖项
class Database {
public void connect() {
System.out.println("Connecting to database...");
}
}
// 定义需要依赖注入的组件
class UserService {
private final Database database;
// 通过构造函数注入依赖项
public UserService(Database database) {
this.database = database;
}
public void createUser() {
database.connect();
System.out.println("Creating a new user...");
}
}
// Spring配置类
@Configuration
class AppConfig {
@Bean
public Database database() {
return new Database();
}
@Bean
public UserService userService(Database database) {
return new UserService(database);
}
}
// 使用Spring容器获取bean并调用方法
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
userService.createUser();
setter注入
setter注入是通过类的setter方法来注入依赖对象的。Spring在创建bean实例后,会调用相应的setter方法将依赖对象注入。这种方式允许在bean实例化后再设置依赖对象,提供了更大的灵活性。
代码示例:
// 定义依赖项
class Database {
public void connect() {
System.out.println("Connecting to database...");
}
}
// 定义需要依赖注入的组件
class UserService {
private Database database;
// 通过setter方法注入依赖项
public void setDatabase(Database database) {
this.database = database;
}
public void createUser() {
database.connect();
System.out.println("Creating a new user...");
}
}
// Spring配置类
@Configuration
class AppConfig {
@Bean
public Database database() {
return new Database();
}
@Bean
public UserService userService() {
UserService userService = new UserService();
userService.setDatabase(database());
return userService;
}
}
// 使用Spring容器获取bean并调用方法
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean(UserService.class);
userService.createUser();
区别总结
- 注入时机:构造函数注入在bean实例化时就会注入依赖对象,而setter注入在bean实例化后会通过setter方法注入依赖对象。
- 灵活性:setter注入提供了更大的灵活性,允许在bean实例化后再设置依赖对象,而构造函数注入则要求依赖对象在bean实例化时就必须提供。
- 必填性:构造函数注入的依赖项通常是必填的,因为构造函数必须被调用才能创建实例;而setter注入的依赖项可以是可选的,因为setter方法可以在任何时候被调用。
- 代码风格:构造函数注入通常更符合不可变对象的设计原则,因为一旦对象被创建,依赖项就不能再被修改;而setter注入则允许在对象生命周期中修改依赖项。