spring 依赖注入的好处
spring框架通过依赖注入,对象之间的依赖关系由 Spring 容器来管理,而不是在代码中硬编码。
这意味着一个类不再需要自己创建和管理其依赖的对象,而是由 Spring 容器将依赖的对象注入到类中。
例如:
在一个用户管理系统中,UserService
类依赖于 UserDao
类,使用 Spring 的依赖注入,UserService
类不需要在内部使用 new
关键字创建 UserDao
的实例,而是由 Spring 容器将 UserDao
的实例注入到 UserService
中。这样,UserService
与 UserDao
的实现细节解耦,当 UserDao
的实现发生变化时,UserService
类不需要进行修改。
场景一:更换 UserDao
的实现类
原理
Spring 的自动注入基于依赖倒置原则,让 UserService
依赖于抽象(接口)而非具体实现。当需要更换 UserDao
实现类时,只需在 Spring 的配置中调整注入的具体实现类,而 UserService
类本身依赖的是抽象接口,不会受到实现类更换的影响。
代码示例
1. 定义 UserDao
接口
// UserDao 接口,定义用户数据访问的方法
public interface UserDao {
void saveUser();
}
2. 实现 UserDao
接口
// 旧的 UserDao 实现类
import org.springframework.stereotype.Repository;
@Repository
public class OldUserDao implements UserDao {
@Override
public void saveUser() {
System.out.println("使用旧方法保存用户信息");
}
}
// 新的 UserDao 实现类
import org.springframework.stereotype.Repository;
@Repository
public class NewUserDao implements UserDao {
@Override
public void saveUser() {
System.out.println("使用新方法保存用户信息");
}
}
3. 定义 UserService
类
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
private UserDao userDao;
@Autowired
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void createUser() {
userDao.saveUser();
}
}
在 UserService
类中,构造函数通过 @Autowired
注解注入 UserDao
接口的实现类。UserService
只依赖于 UserDao
接口,不关心具体是哪个实现类。
4. Spring 配置类(使用 Java 配置)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
// 这里可以选择注入旧的实现类
// @Bean
// public UserDao userDao() {
// return new OldUserDao();
// }
// 也可以选择注入新的实现类
@Bean
public UserDao userDao() {
return new NewUserDao();
}
@Bean
public UserService userService(UserDao userDao) {
return new UserService(userDao);
}
}
场景二:UserDao
构造函数发生变化
代码示例
首先,我们有一个简单的 UserDao
类和 UserService
类,UserService
类手动创建 UserDao
实例。
// UserDao 类,用于处理用户数据访问
class UserDao {
public UserDao() {
System.out.println("UserDao 实例被创建");
}
public void saveUser() {
System.out.println("保存用户信息");
}
}
// UserService 类,用于处理用户业务逻辑,依赖于 UserDao
class UserService {
private UserDao userDao;
public UserService() {
this.userDao = new UserDao();
}
public void createUser() {
userDao.saveUser();
}
}
// 测试类
public class Main {
public static void main(String[] args) {
UserService userService = new UserService();
userService.createUser();
}
}
在这个初始代码中,UserService
类的构造函数里手动使用 new
关键字创建了 UserDao
实例。
构造函数变化
现在,假设 UserDao
的需求发生了变化,需要在构造函数中传入一个数据库连接字符串。
// 修改后的 UserDao 类,构造函数需要传入数据库连接字符串
class UserDao {
private String dbConnectionString;
public UserDao(String dbConnectionString) {
this.dbConnectionString = dbConnectionString;
System.out.println("UserDao 实例被创建,使用数据库连接字符串: " + dbConnectionString);
}
public void saveUser() {
System.out.println("使用 " + dbConnectionString + " 保存用户信息");
}
}
// UserService 类,由于 UserDao 构造函数变化,需要修改
class UserService {
private UserDao userDao;
public UserService() {
// 这里需要修改,因为 UserDao 构造函数发生了变化
this.userDao = new UserDao("jdbc:mysql://localhost:3306/mydb");
}
public void createUser() {
userDao.saveUser();
}
}
// 测试类
public class Main {
public static void main(String[] args) {
UserService userService = new UserService();
userService.createUser();
}
}
可以看到,由于 UserDao
的构造函数发生了变化,UserService
类的构造函数也必须进行修改,这就体现了 UserService
与 UserDao
实现细节的紧密耦合。