> 技术文档 > 从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(1)

从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(1)

目录

前言

为什么我们需要Spring?

传统方式 vs Spring方式

传统开发方式的痛点

1. 对象创建的噩梦

2. 配置地狱

3. 测试的痛苦

Spring带来的革命性改变

1. 告别手动创建对象

2. 配置变得简单

3. 测试变得轻松

真实场景模拟:一个电商系统的对比

你准备好了吗?

结尾:


前言

时光如白驹过隙,一晃笔者又小半个月没更新了,也许无人在意笔者为何没更新了,但笔者还是想通报一下, 笔者这段时间一方面在备战期末考试,另一方面也在梳理学习笔记。

现在,决定开启 Spring 系列博客的正式旅程。  

本篇将聚焦 Spring 的核心思想之一 —— IoC(控制反转)与 DI(依赖注入)。希望与大家一同深入探讨,让 Spring 的“魔法”不再遥不可及。

为什么我们需要Spring?

在深入学习Spring的IoC(控制反转)和DI(依赖注入)之前,让我们先来看看一个简单的对比,你会立刻感受到Spring的魅力。

传统方式 vs Spring方式

传统的Java开发方式:

public class OrderController { private OrderService orderService; private PaymentService paymentService; private EmailService emailService; public OrderController() { // 手动创建所有依赖对象 this.orderService = new OrderService(); this.paymentService = new PaymentService(); this.emailService = new EmailService(); } public void processOrder(Order order) { orderService.saveOrder(order); paymentService.processPayment(order); emailService.sendConfirmation(order); }}

 使用 Spring 框架:

@RestControllerpublic class OrderController { @Autowired private OrderService orderService; @Autowired private PaymentService paymentService; @Autowired private EmailService emailService; @PostMapping(\"/orders\") public void processOrder(@RequestBody Order order) { orderService.saveOrder(order); paymentService.processPayment(order); emailService.sendConfirmation(order); }}

看起来差别不大?让我们继续往下看...

传统开发方式的痛点

1. 对象创建的噩梦

想象一下,当你的项目变得复杂时:

public class OrderService { private UserRepository userRepository; private ProductRepository productRepository; private InventoryService inventoryService; private DiscountService discountService; private AuditService auditService; public OrderService() { // 每个依赖都需要手动创建 this.userRepository = new UserRepository(); this.productRepository = new ProductRepository(); this.inventoryService = new InventoryService(); this.discountService = new DiscountService(); this.auditService = new AuditService(); // 但是等等...这些服务可能还有自己的依赖! // UserRepository可能需要DataSource // InventoryService可能需要CacheManager // 这会形成一个复杂的依赖链... }}

问题显而易见:

  •  代码臃肿:构造函数被大量的对象创建代码污染
  •  硬编码依赖:如果要更换实现,必须修改源代码
  •  测试困难:无法轻易mock依赖对象进行单元测试
  •  维护噩梦:依赖关系复杂,牵一发而动全身

2. 配置地狱

还记得那些冗长的XML配置文件吗?

       

3. 测试的痛苦

// 传统方式下的单元测试public class OrderServiceTest { @Test public void testCreateOrder() { // 为了测试OrderService,需要创建所有的依赖 UserRepository userRepo = new UserRepository(); ProductRepository productRepo = new ProductRepository(); InventoryService inventoryService = new InventoryService(); // ...还有更多依赖 OrderService orderService = new OrderService(); // 测试代码比业务代码还复杂! }}

Spring带来的革命性改变

现在,让我们看看Spring是如何优雅地解决这些问题的:

1. 告别手动创建对象

@Servicepublic class OrderService { @Autowired private UserRepository userRepository; @Autowired private ProductRepository productRepository; @Autowired private InventoryService inventoryService; // 构造函数变得干净简洁 // 所有依赖由Spring自动注入 public void createOrder(Order order) { // 专注于业务逻辑,而不是对象创建 User user = userRepository.findById(order.getUserId()); // ...业务逻辑 }}

2. 配置变得简单

@Configuration@ComponentScan(\"com.example\")public class AppConfig { // 一个注解胜过千行XML}// 或者更简单,使用Spring Boot@SpringBootApplicationpublic class Application { // 零配置启动!}

3. 测试变得轻松

@ExtendWith(SpringExtension.class)class OrderServiceTest { @Mock private UserRepository userRepository; @InjectMocks private OrderService orderService; @Test void testCreateOrder() { // 轻松mock依赖,专注测试业务逻辑 when(userRepository.findById(1L)).thenReturn(mockUser); orderService.createOrder(testOrder); verify(userRepository).findById(1L); }}

真实场景模拟:一个电商系统的对比

让我们通过一个真实的电商系统场景来感受这种差异:

我们假设一个用户下单,系统需要:

  1. 扣减库存

  2. 执行支付

  3. 返回下单结果

传统方式的订单处理类:

// 传统方式:自己创建依赖对象public class OrderService { private PaymentService paymentService; private InventoryService inventoryService; public OrderService() { this.paymentService = new PaymentService(); // 主动创建依赖对象 this.inventoryService = new InventoryService(); } public void createOrder() { inventoryService.deductStock(); paymentService.pay(); System.out.println(\"订单创建成功!\"); } public static void main(String[] args) { OrderService orderService = new OrderService(); orderService.createOrder(); }}class PaymentService { public void pay() { System.out.println(\"支付成功!\"); }}class InventoryService { public void deductStock() { System.out.println(\"库存扣减成功!\"); }}

 问题:

  • 代码耦合严重,OrderService 无法方便地更换或测试依赖组件

  • 不利于维护,不利于扩展,不易于单元测试。

Spring方式的订单处理类:

1. 定义各个组件

import org.springframework.stereotype.Service;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;@Servicepublic class OrderService { @Autowired private PaymentService paymentService; @Autowired private InventoryService inventoryService; public void createOrder() { inventoryService.deductStock(); paymentService.pay(); System.out.println(\"订单创建成功!\"); }}@Serviceclass PaymentService { public void pay() { System.out.println(\"支付成功!\"); }}@Serviceclass InventoryService { public void deductStock() { System.out.println(\"库存扣减成功!\"); }}

 2. 启动类模拟运行

import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ApplicationContext;@SpringBootApplicationpublic class ECommerceApp { public static void main(String[] args) { ApplicationContext context = SpringApplication.run(ECommerceApp.class, args); OrderService orderService = context.getBean(OrderService.class); orderService.createOrder(); }}

你准备好了吗?

看到这里,你是否已经感受到了Spring框架的强大魅力?它不仅仅是一个工具,更是一种编程思想的革命。

Spring解决的不仅仅是技术问题,更是开发效率和代码质量的问题:

  •  让开发者专注业务逻辑,而不是基础设施
  •  让代码更加简洁、优雅、可维护
  •  让测试变得简单,提高代码质量
  •  让团队协作更加高效

那么问题来了:Spring是如何做到这一切的?

答案就在IoC(控制反转)和DI(依赖注入)这两个核心概念中。理解了它们,你就理解了Spring的灵魂,也就掌握了现代Java开发的精髓。

接下来,让我们深入探索这个让Java开发变得如此优雅的奥秘吧!

结尾:

如果你读到了这里,请不要因为戛然而止感到惊讶,因为笔者想要在下一篇博客中详细介绍 Ioc & DI

因此这是引子博客,笔者希望读者明白为什么需要IoC和DI,珍惜Spring带来的便利。