从问题出发学懂Spring

Elon Musk 讲到如何快速学习新知识,假如要学习火箭发动机,传统的理念是,先学习有关火箭的所有知识,比如有哪些型号的螺丝刀,最后从0-1造火箭发动机。而效率更高的学习方式,是拿过来一个火箭发动机,把他拆解开,看看有哪些组成部分。怎么拆?需要A型号的螺丝刀来拆开发动机。Opps!A型号的螺丝刀有这个作用。

P.S. 我将以这种方法向大家讲解java的常用框架,以及设计模式,有兴趣的可以点个关注,会持续不定期更新,本系列举例由chatGPT生成

相比传统的学习方式,大多的学习Spring的blog都从DI和AOP的概念讲起,哪怕举例一些例子,依然觉得有些抽象。

现在我从问题出发,倒着学习spring

Question 1:有DI和没有DI对我写代码有什么影响(我们先不说DI具体的概念)

a、没有DI

假设有一个订单服务(OrderService),它需要使用用户服务(UserService)来获取用户信息。在没有使用 Spring 框架的情况下,我们可能会这样实现:

public class OrderService {
    private UserService userService;
    
    public OrderService() {
        this.userService = new UserService(); // 手动创建 UserService 实例
    }
    
    public void processOrder(int userId, String productId) {
        // 根据用户ID获取用户信息
        User user = userService.getUserById(userId);
        
        // 处理订单逻辑
        // ...
    }
}

在上面的例子中,OrderService 类在构造函数中手动创建了 UserService 实例,并使用该实例来获取用户信息。这种方式存在一些问题,比如:

  1. OrderService 类与 UserService 类之间的耦合度较高,不利于代码的维护和扩展。
  2. 如果 UserService 类的实现发生变化,需要修改 OrderService 类的构造函数,违反了开闭原则。
  3. 单元测试时难以进行模块的替换和测试。

b、引入DI

public class OrderService {
    private UserService userService;
    
    // 使用构造函数注入依赖对象
    public OrderService(UserService userService) {
        this.userService = userService;
    }
    
    public void processOrder(int userId, String productId) {
        // 根据用户ID获取用户信息
        User user = userService.getUserById(userId);
        
        // 处理订单逻辑
        // ...
    }
}

在上面的例子中,OrderService 类的构造函数接受一个 UserService 类的实例作为参数,并将该实例赋值给类的成员变量。这样,Spring 框架在创建 OrderService 实例时会自动注入 UserService 实例,实现了依赖注入。这种方式可以减少类之间的耦合度,提高代码的可维护性和可测试性。

这时,就算我不说DI是什么,大家也知道DI有什么作用了,保险起见,还是写一下概念

依赖注入(Dependency Injection): Spring 框架引入了依赖注入(DI)机制,通过将组件之间的依赖关系委托给容器管理,实现了松耦合和可测试性。开发人员不再需要手动管理对象之间的依赖关系,而是通过配置文件或注解告诉 Spring 框架如何注入依赖,从而简化了代码和提高了灵活性。

Question 2:这时我们应该继续发问,为什么spring框架可以实现DI?

我们首先将每个类想象成高达的组件,有的是小拇指,有的是手掌,拼高达时,我们要把小拇指拼到手掌上。说明手掌需要小拇指,手掌是主组件,小拇指是普通组件。

举个新的例子,UserController类调用了UserService,UserController是主组件,UserService是普通组件,我们用@Controller和@Component来表示主组件和普通组件。对了,这些组件有个统一的名字,Bean

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class UserController {
    private UserService userService;

    // 构造函数注入
    @Autowired
    public UserController(UserService userService) {
        this.userService = userService;
    }

    public String displayUserInfo() {
        return userService.getUserInfo();
    }
}
public class UserService {
    public String getUserInfo() {
        return "User information from UserService";
    }
}

贴上八股:在实际开发中,@Component@Controller 注解都可以用来标识组件,它们的作用是相同的,都能够让 Spring 框架自动扫描并注册为 Bean。但是,为了更好地表达代码的用途和意图,建议按照它们的语义规范来使用,即 @Component 用于普通的组件类,@Controller 用于标识控制器类。这样可以使代码更加清晰易懂,符合开发规范

回到问题,spring框架把每个类型变成一个组件,相互依赖时,只要把两块组件拼起来就行。

贴上八股

Spring 框架通过控制反转(IoC)实现了对象的创建、管理和依赖注入。以下是 Spring 实现 IoC 的主要步骤和原理:

  1. 配置元数据: 在 Spring 中,通常通过 XML 文件、Java 注解或者 Java 代码来配置应用程序的组件和它们之间的依赖关系。这些配置信息称为配置元数据。

  2. Bean 定义: 在配置元数据中,需要明确指定哪些类是需要由 Spring 管理的 Bean,并且提供了 Bean 的属性、构造函数参数、依赖关系等信息。在 Spring 中,可以使用 <bean> 标签(XML 配置)、@Component 注解(注解配置)或者 @Bean 注解(Java 代码配置)来定义 Bean。

  3. Bean 工厂: Spring 框架会读取配置元数据,并根据配置信息来创建和管理 Bean。Spring 的 Bean 工厂负责实例化 Bean,并将它们放入容器中。

  4. 依赖注入: 当 Bean 被创建并放入容器中后,Spring 框架会根据配置信息自动注入 Bean 之间的依赖关系。依赖注入的方式可以通过构造函数注入、Setter 方法注入、字段注入等方式来实现。

  5. 生命周期管理: Spring 容器管理 Bean 的生命周期,包括初始化、销毁等阶段。可以通过配置初始化方法和销毁方法来管理 Bean 的生命周期。

总的来说,Spring 实现 IoC 的关键在于它通过配置元数据和 Bean 工厂来管理应用程序的组件,并根据依赖关系自动注入 Bean,从而实现了对象的解耦合、灵活性和可测试性。通过控制反转,Spring 将对象的创建和依赖关系的管理从应用程序中解耦出来,交给了 Spring 容器来管理,从而降低了应用程序的耦合度,提高了代码的可维护性和可测试性。

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值