跳转到内容

Spring依赖注入

来自代码酷

Spring依赖注入[编辑 | 编辑源代码]

介绍[编辑 | 编辑源代码]

依赖注入(Dependency Injection,简称DI)是Spring框架的核心特性之一,它允许对象通过外部容器(如Spring IoC容器)来获取其依赖的其他对象,而不是由对象自身创建或查找依赖项。这种方式降低了代码的耦合度,提高了可测试性和可维护性。

在Spring中,依赖注入主要有三种方式:

  • 构造器注入(Constructor Injection)
  • Setter注入(Setter Injection)
  • 字段注入(Field Injection)

依赖注入的类型[编辑 | 编辑源代码]

构造器注入[编辑 | 编辑源代码]

构造器注入是通过类的构造函数来注入依赖项。这是Spring官方推荐的方式,因为它可以确保依赖项在对象创建时就被注入,并且依赖项不可变(final)。

public class UserService {
    private final UserRepository userRepository;

    // 构造器注入
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public void saveUser(User user) {
        userRepository.save(user);
    }
}

在Spring配置中,可以通过XML或注解方式配置构造器注入:

<bean id="userRepository" class="com.example.UserRepositoryImpl" />
<bean id="userService" class="com.example.UserService">
    <constructor-arg ref="userRepository" />
</bean>

Setter注入[编辑 | 编辑源代码]

Setter注入是通过类的setter方法来注入依赖项。这种方式允许依赖项在对象创建后动态变更。

public class OrderService {
    private PaymentService paymentService;

    // Setter注入
    public void setPaymentService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }

    public void processOrder(Order order) {
        paymentService.processPayment(order);
    }
}

XML配置示例:

<bean id="paymentService" class="com.example.PaymentServiceImpl" />
<bean id="orderService" class="com.example.OrderService">
    <property name="paymentService" ref="paymentService" />
</bean>

字段注入[编辑 | 编辑源代码]

字段注入是直接在字段上使用注解(如`@Autowired`)来注入依赖项。这种方式虽然简洁,但不利于测试和代码的可维护性。

public class ProductService {
    @Autowired
    private InventoryService inventoryService;

    public void checkStock(Product product) {
        inventoryService.checkStock(product);
    }
}

依赖注入的实际应用[编辑 | 编辑源代码]

场景:电商系统中的订单处理[编辑 | 编辑源代码]

假设有一个电商系统,订单处理服务(`OrderService`)依赖于支付服务(`PaymentService`)和库存服务(`InventoryService`)。通过依赖注入,可以灵活地替换具体的实现类。

public class OrderService {
    private final PaymentService paymentService;
    private final InventoryService inventoryService;

    // 构造器注入
    public OrderService(PaymentService paymentService, InventoryService inventoryService) {
        this.paymentService = paymentService;
        this.inventoryService = inventoryService;
    }

    public void placeOrder(Order order) {
        inventoryService.reserveStock(order);
        paymentService.charge(order);
    }
}

使用注解配置依赖注入[编辑 | 编辑源代码]

Spring支持使用`@Autowired`或`@Resource`注解来自动装配依赖项。

@Service
public class OrderService {
    private final PaymentService paymentService;
    private final InventoryService inventoryService;

    @Autowired
    public OrderService(PaymentService paymentService, InventoryService inventoryService) {
        this.paymentService = paymentService;
        this.inventoryService = inventoryService;
    }
}

依赖注入的优势[编辑 | 编辑源代码]

  • 解耦:对象不需要知道如何创建或查找依赖项。
  • 可测试性:可以轻松替换依赖项的实现(如使用Mock对象)。
  • 可维护性:依赖关系清晰,便于重构和扩展。

依赖注入的底层原理[编辑 | 编辑源代码]

Spring IoC容器通过以下步骤实现依赖注入: 1. 扫描并注册Bean定义。 2. 解析Bean之间的依赖关系。 3. 创建Bean实例并注入依赖项。

graph TD A[启动Spring容器] --> B[扫描Bean定义] B --> C[解析依赖关系] C --> D[创建Bean实例] D --> E[注入依赖项]

常见问题与解决方案[编辑 | 编辑源代码]

循环依赖问题[编辑 | 编辑源代码]

当两个Bean互相依赖时,可能会导致循环依赖问题。例如:

@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB;
}

@Service
public class ServiceB {
    @Autowired
    private ServiceA serviceA;
}

解决方案

  • 使用构造器注入时,Spring会抛出`BeanCurrentlyInCreationException`。
  • 使用Setter或字段注入时,Spring可以通过三级缓存解决循环依赖。

依赖冲突[编辑 | 编辑源代码]

当有多个相同类型的Bean时,Spring会抛出`NoUniqueBeanDefinitionException`。

解决方案

  • 使用`@Qualifier`注解指定Bean名称。
  • 使用`@Primary`注解标记首选Bean。

总结[编辑 | 编辑源代码]

依赖注入是Spring框架的核心机制,它通过外部容器管理对象及其依赖关系,提高了代码的灵活性和可维护性。开发者应根据具体场景选择合适的注入方式(推荐优先使用构造器注入),并注意避免循环依赖和依赖冲突问题。