通俗易懂扫盲Spring Framework

一、什么是Spring

Spring 是一款开源的轻量级 Java 开发框架,旨在提高开发人员的开发效率以及系统的可维护性。

我们一般说 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以很方便地协助我们进行开发,比如说 Spring 支持 IoC(Inversion of Control:控制反转) 和 AOP(Aspect-Oriented Programming:面向切面编程)、可以很方便地对数据库进行访问、可以很方便地集成第三方组件(电子邮件,任务,调度,缓存等等)、对单元测试支持比较好、支持 RESTful Java 应用程序的开发。

一句话说:Spring 是包含了众多工具方法的 IoC 容器

二、IoC详解

IoC: Inversion of Control (控制反转), 也就是说 Spring 是⼀个"控制反转"的容器

控制反转:控制权 发生反转

什么的控制权发生反转:获得依赖对象的过程 发生反转

以前创建对象都是直接new出来的。

现在通过IoC容器你可以将创建对象的任务交给IoC容器(让它帮你装着),需要的时候在通过DI(依赖注入)拿出来直接用

2.1简单例子具体了解控制反转

不使用IoC造车:先造轮子,根据轮子造底盘,根据底盘造车身,然后得到车(注意:这里轮子固定长度)

java 复制代码
public class NewCarExample {
    public static void main(String[] args) {
        Car car = new Car();
        car.run();
    }
    
    /**
     * 汽车对象
     */
    static class Car {
        private Framework framework;
        
        public Car() {
            framework = new Framework();
            System.out.println("Car init....");
        }
        
        public void run() {
            System.out.println("Car run...");
        }
    }
    
    /**
     * 车身类
     */
    static class Framework {
        private Bottom bottom;
        
        public Framework() {
            bottom = new Bottom();
            System.out.println("Framework init...");
        }
    }
    
    /**
     * 底盘类
     */
    static class Bottom {
        private Tire tire;
        
        public Bottom() {
            this.tire = new Tire();
            System.out.println("Bottom init...");
        }
    }
    
    /**
     * 轮胎类
     */
    static class Tire {
        // 尺寸
        private int size;
        
        public Tire() {
            this.size = 17;
            System.out.println("轮胎尺寸:" + size);
        }
    }
}

突然有一天,有客户要18尺寸的轮子,但我是写死了只有17的那咋办,总不能抛弃17的市场吧?接下来了我把所有构造方法都加入尺寸参数:

之前(例子)

java 复制代码
static class Bottom {
        private Tire tire;
        
        public Bottom() {
            this.tire = new Tire();
            System.out.println("Bottom init...");
        }
    }

之后

java 复制代码
static class Bottom {
        private Tire tire;
        
        public Bottom(int size) {
            this.tire = new Tire();
            System.out.println("Bottom init...");
        }
    }

后来又有客户想要换轮子颜色,还想换不同摩擦轮胎,那我是不是得把所有方法都加个新属性?那也太麻烦了,这时问题就出现了,每个类之间依赖太严重,用IoC试试咋样:

java 复制代码
public class IocCarExample {
    public static void main(String[] args) {
        Tire tire = new Tire(20);
        Bottom bottom = new Bottom(tire);
        Framework framework = new Framework(bottom);
        Car car = new Car(framework);
        car.run();
    }
    
    static class Car {
        private Framework framework;
        
        public Car(Framework framework) {
            this.framework = framework;
            System.out.println("Car init....");
        }
        
        public void run() {
            System.out.println("Car run...");
        }
    }
    
    static class Framework {
        private Bottom bottom;
        
        public Framework(Bottom bottom) {
            this.bottom = bottom;
            System.out.println("Framework init...");
        }
    }
    
    static class Bottom {
        private Tire tire;
        
        public Bottom(Tire tire) {
            this.tire = tire;
            System.out.println("Bottom init...");
        }
    }
    
    static class Tire {
        private int size;
        
        public Tire(int size) {
            this.size = size;
            System.out.println("轮胎尺寸:" + size);
        }
    }
}

这时候你会发现,无论你轮子咋改,那从下到上的整体基本没啥变化了

2.2 IoC容器作用

1.资源集中管理: IoC容器会帮我们管理⼀些资源(对象等), 我们需要使用时, 只需要从IoC容器中去取就可以了

  1. 我们在创建实例的时候不需要了解其中的细节, 降低了使用资源双方的依赖程度, 也就是耦合度

反转前:UserService service = new UserServiceImpl();

你控制了:用哪个类,什么时候创建,怎么创建

反转后:@Autowired UserService service;

你只用说:我要 UserService

Spring决定:用哪个实现,什么时候创建,生命周期怎么管

2.3 IoC 的底层"执行手"------反射 (Reflection)

我们已经知道 IoC 是把对象的控制权交出去,但 Spring 拿到控制权后,它是怎么在不写 new 的情况下把对象造出来的呢?答案就是:反射

1. 为什么不能用 new

在传统开发(凡人视角)中,我们要一个对象必须硬编码:
User user = new User();

这就像是把家具直接焊死在房子的地板上。如果你想换个款式的家具,就必须拆房子(改代码、重新编译)。

2. 反射:上帝视角

反射让程序拥有了"透视眼"和"动态操纵"的能力。

  • 正常顺序:你看到菜单(Class),然后点菜(new),厨师给你上菜(Object)。
  • 反射顺序:JVM 运行到一半,Spring 跑过来翻箱倒柜,通过一个字符串名字(比如 "com.spring.User"),直接反向推导出这个类的构造器、方法和属性,然后强行把它实例化出来。

反射的本质 :JVM 在运行时,通过解读 .class 字节码文件,动态地创建对象。

  • IoC 的实现逻辑 :Spring 容器读取你的注解(如 @Service)或 XML 配置,获取到类的全路径字符串,然后利用反射机制 调用构造函数。这样,代码里就不再出现 new,实现了真正的解耦。

2.4 IoC 的底层"情报员"------SPI 机制

如果说反射 解决了"怎么造对象"的问题,那么 SPI (Service Provider Interface) 机制就解决了"到底该造哪一个对象"的问题。

1. 核心矛盾:主程序不知道该选谁

想象你开发了一个通用的打印机驱动程序(主程序),你定义了一个接口 print()。但是世界上有爱普生、惠普、佳能各种打印机(第三方实现)。

你总不能在驱动代码里写:
if (品牌 == 惠普) { new HPPrinter(); }

否则每出一个新品牌,你都要改驱动代码。

2. SPI 的解法:约定优于配置

SPI 就像是一个"插件发现机制 "。主程序只管定义接口标准,具体的实现类由第三方厂商去写。

那主程序怎么知道厂商把实现类写在哪了?对暗号!

以 JDBC 驱动为例,看看这个"暗号"是怎么对上的:

  1. 约定地点 :所有第三方 jar 包必须在 META-INF/services/META-INF/spring.factories 目录下放一个文件。
  2. 情报内容 :文件里写上实现类的全路径名(例如:com.mysql.cj.jdbc.Driver)。
  3. 自动扫描:当 Spring Boot 启动时,它会像侦察兵一样扫描所有 jar 包里的这些特定目录。
  4. 反射加载 :一旦扫到了"情报",Spring 就会立刻拿起反射这个工具,根据文件里的字符串把对象创建出来。

3. 总结:IoC 的工作流程

  • SPI :负责" "。它在茫茫多的 jar 包中发现各种实现类,解决了"决定创建谁"的问题。
  • 反射 :负责" "。它根据 SPI 找来的字符串名字,动态创建出实例,解决了"怎么创建"的问题。

结果:你只需要引入一个 Maven 依赖(比如 MySQL 驱动),Spring 就能自动识别并加载它。你一行代码都没改,但系统功能却增强了,这就是 IoC 的魅力。

2.5 SPI,IoC,DI如何互相配合

SPI 决定用谁

反射创建对象

注册到 IOC 容器

DI 注入到别的 Bean

三、DI

DI指的是依赖注入

容器在运行期间, 动态的为应用程序提供运行时所依赖的资源,称之为依赖注入。

比如这个代码就把轮子注入到了底盘里
IoC是一种思想,那么DI就是实现这个思想的具体方式

java 复制代码
 static class Bottom {
        private Tire tire;
        
        public Bottom(Tire tire) {
            this.tire = tire;
            System.out.println("Bottom init...");
        }
    }

3.1DI的注入方式

1.属性注入(利用@Autowired)

java 复制代码
@Controller
public class UserController {
 //注⼊⽅法1: 属性注⼊
 	@Autowired
 	private UserService userService;
 	
 	public void sayHi(){
 		System.out.println("hi,UserController...");
 		userService.sayHi();
 	}
}

2.构造方法注入

java 复制代码
@Controller
public class UserController2 {
 //注⼊⽅法2: 构造⽅法
 	private UserService userService;
 	@Autowired
 	public UserController2(UserService userService) {
 		this.userService = userService;
 	}
 	public void sayHi(){
 		System.out.println("hi,UserController2...");
 		userService.sayHi();
 	}
}

如果类只有⼀个构造方法,那么 @Autowired 注解可以省略;如果类中有多个构造方法,那么需要添加上 @Autowired 来明确指定到底使用哪个构造方法。

还要一个Setter注入可自行查看咋用。

3.2 注入方式优缺点

属性注入

  • 优点:简洁,使用方便
  • 缺点
    • 只能用于 IoC 容器,如果是非 IoC 容器不可用,并且只有在使用时才会出现 NPE(空指针异常)
    • 不能注入 final 修饰的属性

构造函数注入(Spring 4.X 推荐)

  • 优点
    • 可以注入 final 修饰的属性
    • 注入的对象不会被修改
    • 依赖对象在使用前一定会被完全初始化,因为依赖是在构造方法中执行的,而构造方法在类加载阶段就会执行
    • 通用性好,构造方法是 JDK 支持的,更换任何框架都适用
  • 缺点
    • 注入多个对象时,代码会比较繁琐

四、Bean 容器

我们知道 Spring 是一个 IoC 容器,而这个容器里存放的一个个对象,我们就管它们叫 Bean


4.1 注册 Bean(把对象交给容器管理)

在 Spring 中,所有被 IOC 容器管理的对象都称为 Bean。

要让 Spring 负责对象的创建、依赖注入以及生命周期管理,第一步就是将对象注册为 Bean。

从底层实现角度来看,注册 Bean 的过程本质上是向 IOC 容器中注册一份 BeanDefinition(Bean 的定义信息)。

Spring 在启动阶段会根据这些定义,通过反射机制创建对象并进行统一管理。

目前常见的 Bean 注册方式主要分为以下两类。


4.1.1 基于类级别注解的 Bean 注册(组件扫描)

这是最常用、自动化程度最高的一种 Bean 注册方式,依赖于组件扫描(Component Scan)机制。

Spring 在启动时会根据配置的扫描路径,对指定包及其子包下的类进行扫描。

当容器通过反射读取到类上标注了组件相关注解时,便会将该类解析为一个 BeanDefinition,并注册到 IOC 容器中。


(1)核心组件注解

@Component 是最基础的组件注解,用于标识一个普通的 Spring 组件。

只要类上标注了该注解,并且位于组件扫描范围内,就会被自动注册为 Bean。

Spring 启动时会执行以下流程:

1.根据配置的扫描路径(如 @ComponentScan)

2.扫描指定包及其子包下的所有 .class 文件

3.通过反射读取类上的注解信息

4.发现 @Component 注解

5.生成对应的 BeanDefinition 并注册到 IOC 容器中

6.至此,该类正式成为一个由 Spring 管理的 Bean。


(2)语义化派生注解(常见"五大注解")

为了增强代码的语义表达能力,Spring 在 @Component 的基础上提供了一组语义化注解,用于标识类在系统中的职责。

  • @Component:通用组件,适用于不明确分层的类
  • @Service:业务层组件,用于标识业务逻辑类
  • @Controller:控制层组件,用于处理 Web 请求
  • @Repository:持久层组件,用于数据访问相关类
  • @Configuration:配置类,用于集中定义 Bean

这些注解在功能层面等价,均可将类注册为 Bean,不同之处在于语义和部分附加功能。


(3)组件扫描的前提条件

类级别注解生效的前提是开启组件扫描。

如@SpringBootApplication

Spring Boot 默认会扫描启动类 所在包及其子包下的所有组件,而在传统 Spring 项目中,则需要显式指定扫描路径。

如@ComponentScan("com.example")


4.1.2 基于方法级别注解的 Bean 注册(@Bean)

当需要将第三方库中的类,或无法直接修改源码的类交由 Spring 管理时,通常采用方法级别的 Bean 注册方式。

基本用法:

java 复制代码
@Configuration
public class AppConfig {

    @Bean
    public DataSource dataSource() {
        return new DruidDataSource();
    }
}
Spring 在启动时会执行以下操作:
识别 @Configuration 配置类
扫描配置类中标注了 @Bean 的方法
通过反射调用该方法
将方法返回的对象注册为 Bean

(1)@Bean 的基本特性
  • Bean 的名称默认由方法名决定
  • Bean 的类型由方法返回值类型决定
  • Bean 的生命周期完全由 IOC 容器管理
  • 方法参数可以自动从容器中注入其他 Bean

(2)@Bean 与配置类的关系

@Bean 通常配合 @Configuration 使用,其原因在于:

@Configuration 类会被 CGLIB 动态代理,能确保同一个 @Bean 方法在容器中只创建一个实例(单例),如果缺少 @Configuration,@Bean 方法可能会被多次调用,从而破坏单例语义


4.1.3 两种 Bean 注册方式的对比

对比维度 类级别注解 方法级别注解
标注位置 方法
是否依赖组件扫描
适用对象 自定义业务类 第三方或复杂对象
控制粒度 较低 较高
常见使用场景 业务组件 数据源、配置对象

4.2 装配 Bean(依赖注入 DI 的具体实现)

食材都进厨房了,但"锅"和"铲子"是分开存放的。当你需要炒菜时,厨房得自动把铲子递到锅的手里。这个自动递工具 的过程,就叫装配 Bean

在代码中,我们最常用的"递工具"方式就是 @Autowired

Spring 提供了三种递工具的方式(同上):

  1. 属性注入(Field Injection)
    直接在变量上面加 @Autowired
  2. Setter 注入(Setter Injection)
    通过 Setter 方法注入。
  3. 构造方法注入(Constructor Injection)
    在类初始化的时候就要求把依赖传进来。

@Autowired 与 @Resource 的区别

  • 来源不同

    • @Autowired 是 Spring 框架提供的注解
    • @Resource 是 JDK 提供的注解(javax.annotation.Resource)
  • 注入方式不同

    • @Autowired 默认按照类型(byType)注入
    • @Resource 默认按照名称(byName)注入
  • 功能差异

    • @Resource 支持更多参数设置,如 name 属性可指定具体 Bean 名称
    • @Resource 是 JSR-250 标准注解,更换框架时兼容性更好
    • @Autowired 配合 @Qualifier 注解可实现按名称注入
  • 使用场景

    • 推荐使用 @Resource:需要按名称注入或希望保持框架中立性时
    • 使用 @Autowired:明确按类型注入或完全在 Spring 生态中开发时

4.3 容器中对象的生命周期(Bean 的一生)

一个 Bean 从出生到死亡,并不是简单的 new 一下就完了。Spring 容器像个保姆一样,在每个阶段都提供了"服务"。

我们可以把 Bean 的生命周期分为五个阶段:

  1. 实例化(Instantiation)
    • 动作 :Spring 通过反射,在内存中给 Bean 开辟空间。
    • 通俗比喻:中央厨房把面条生产出来了。
  2. 属性赋值(Populate Properties)
    • 动作 :执行 DI(依赖注入),把该对象依赖的其他 Bean 塞进来。
    • 通俗比喻:给面条拌上调料,配上牛肉。
  3. 初始化(Initialization)
    • 动作 :执行一些初始化方法(比如贴了 @PostConstruct 的方法)。
    • 通俗比喻:面条下锅煮熟,正式端上桌变成"牛肉面"。
  4. 使用中(In Use)
    • 动作:Bean 待在容器里,随时等程序调用。
    • 通俗比喻:客人(你的业务逻辑)正在吃这碗面。
  5. 销毁(Destruction)
    • 动作 :容器关闭时,执行销毁方法(比如贴了 @PreDestroy 的方法)。
    • 通俗比喻:客人吃完了,厨房回收碗筷,清理垃圾。

五、AOP(面向切面编程)

5.1 为什么需要 AOP

在实际开发中,系统中往往存在一些与核心业务无关,但又必须统一处理的功能,例如:

  • 日志记录
  • 权限校验
  • 事务管理
  • 性能监控
  • 异常处理

这些功能具有一个共同特点:
它们分散在多个业务方法中,但逻辑高度重复

如果将这些代码直接写进业务方法,会导致:

  • 业务代码被污染
  • 重复代码大量出现
  • 修改一处规则需要改动多个类
  • 违背单一职责原则

AOP 的目的就是:
在不修改业务代码的前提下,对方法进行统一增强


5.2 什么是 AOP

AOP(Aspect Oriented Programming)是一种编程思想,核心目标是关注点分离

在 AOP 中:

  • 核心业务逻辑称为"主线逻辑"
  • 日志、事务等通用功能称为"横切关注点"

AOP 通过在特定的执行位置"横向切入"这些通用逻辑,从而实现对业务行为的统一增强。


5.3 AOP 的核心概念

理解 Spring AOP,必须先理解以下几个关键概念。


(1)切面(Aspect)

切面是横切关注点的抽象表达。

它本质上是一个封装了增强逻辑的模块,用于定义"在哪些地方、做什么增强"。


(2)连接点(Join Point)

连接点是程序执行过程中的一个可被拦截的位置

在 Spring AOP 中,连接点通常指的是方法的执行


(3)切点(Pointcut)

切点是对连接点的筛选规则。

它用于明确说明:哪些方法需要被增强


(4)通知(Advice)

通知是实际执行的增强逻辑。

例如:在方法执行前记录日志、在方法执行后提交事务等。


(5)目标对象(Target)

目标对象是被 AOP 增强的原始业务对象。


(6)代理对象(Proxy)

代理对象是 Spring 为目标对象创建的替身

外部调用的实际上是代理对象,而非目标对象本身。


5.4 Spring AOP 的实现原理

Spring AOP 的核心思想可以总结为一句话:

通过动态代理,在方法调用前后织入增强逻辑

当一个 Bean 需要被 AOP 增强时,Spring 在创建该 Bean 的过程中,会执行以下流程:

  1. 判断该 Bean 是否匹配某个切点规则
  2. 如果匹配,则为该 Bean 创建代理对象
  3. 容器中保存的是代理对象,而不是原始对象
  4. 外部调用通过代理对象间接执行目标方法
  5. 代理在合适的时机执行增强逻辑

5.5 Spring AOP 的两种代理方式

Spring AOP 并不直接操作字节码,而是基于代理机制实现,主要有两种方式。


5.5.1 JDK 动态代理

JDK 动态代理是 Java 原生提供的代理机制。

其特点是:

  • 只能代理实现了接口的类
  • 代理对象与目标对象实现相同的接口
  • 基于接口进行方法拦截

在目标类实现接口的情况下,Spring 默认使用 JDK 动态代理。


5.5.2 CGLIB 动态代理

CGLIB 是一种基于继承的代理方式。

其特点是:

  • 通过生成目标类的子类进行代理
  • 不要求目标类实现接口
  • 依赖字节码增强技术

当目标类没有实现接口时,Spring 会自动使用 CGLIB 动态代理。


5.6 AspectJ 与 Spring AOP 的关系

AspectJ 是一个功能更完整的 AOP 框架。

Spring AOP 借鉴了 AspectJ 的语法体系,但在能力上有所限制:

  • Spring AOP 只能作用于方法级别
  • AspectJ 可以作用于更丰富的连接点

在日常业务开发中,Spring AOP 已经可以满足绝大多数需求。


5.7 AOP 与 IOC 的关系

AOP 并不是独立存在的,它依赖 IOC 容器

  • IOC 负责创建和管理 Bean
  • AOP 在 Bean 创建过程中介入
  • AOP 最终作用于 IOC 容器中的对象

可以理解为:
AOP 是 IOC 的增强机制,而不是替代品


六、Spring MVC(Web 请求是怎么被 Spring 接住的)

一句话:

SpringMVC = 把「HTTP 请求」 →「Java 方法」 →「返回响应」这一整套流程自动化

你写的只是业务逻辑,

真正接请求、解析参数、封装对象、返回页面或 JSON ------
全部由 SpringMVC 在幕后完成。


1. SpringMVC 在 Spring 体系中的位置

可以把 Spring 理解为三层:

  • Spring Core
    • IOC / DI:管理对象的创建和依赖
  • Spring AOP
    • 处理事务、日志等横切逻辑
  • Spring MVC
    • 专门负责 Web 请求处理

SpringMVC 不负责造对象

SpringMVC 负责"请求该调用谁"


2. SpringMVC 的核心组件

1. DispatcherServlet(前端控制器)

一句话记住:

所有 HTTP 请求,都会先到 DispatcherServlet

它是 SpringMVC 的总入口,负责统一调度。


2. Controller(控制器)

  • 标注了 @Controller@RestController
  • 内部方法是真正处理请求的地方

DispatcherServlet 不处理业务

只负责把请求转交给合适的 Controller 方法。


3. HandlerMapping(映射器)

作用:

根据请求路径和请求方式,找到要调用的 Controller 方法

例如:

  • 请求路径是 /user/1
  • 找到对应的某个处理方法

4. HandlerAdapter(适配器)

作用:

真正"执行 Controller 方法"

因为 Controller 方法的形式很多:

  • 有参数 / 没参数
  • 返回页面 / 返回对象

HandlerAdapter 负责"适配并调用"。


5. ViewResolver(视图解析器)

  • 当返回的是页面名时
  • 负责找到真正的页面文件

如果返回的是 JSON(前后端分离),
这个步骤会被跳过


3. SpringMVC 的完整执行流程(重点)

一次请求的完整流程:

  1. 浏览器发送 HTTP 请求
  2. 请求进入 DispatcherServlet
  3. DispatcherServlet 询问 HandlerMapping
  4. 找到对应的 Controller 方法
  5. DispatcherServlet 调用 HandlerAdapter
  6. HandlerAdapter:
    • 解析请求参数
    • 自动注入对象
    • 执行方法
  7. 方法返回结果
  8. DispatcherServlet 处理返回值:
    • 页面 → ViewResolver
    • JSON → 直接写入响应
  9. 浏览器接收响应

核心主线:

请求 → DispatcherServlet → Controller 方法 → 响应


4. @RequestMapping 的本质

一句话解释:

@RequestMapping = 给方法贴路标

告诉 SpringMVC:

  • 什么路径
  • 用什么请求方式
  • 调用哪个方法

类上的 @RequestMapping

作用:

统一路径前缀

常用于模块划分,比如用户模块、订单模块。


方法上的 @RequestMapping

作用:

具体到某一个请求地址和请求方式

SpringMVC 就是靠它完成"请求 → 方法"的映射。


5. @PathVariable 的原理

URL 示例:

/user/1001

SpringMVC 的理解是:

路径中的某一段是变量


@PathVariable 在做什么

SpringMVC 在调用方法前会:

  1. 解析 URL
  2. 提取路径中的值
  3. 自动做类型转换
  4. 注入到方法参数中

你无需自己拆字符串

只需关注业务逻辑


6. 方法参数为什么能自动注入(核心理解)

你会发现:

  • 没有 new
  • 没有解析
  • 参数却自动有值

原因是:

SpringMVC 在调用方法前,执行了一次"参数绑定"


SpringMVC 能自动注入的常见内容

  • 路径变量
  • 请求参数
  • 请求体数据
  • Session 中的数据
  • IOC 容器中的 Bean

本质总结:

SpringMVC = IOC + 反射 + 参数解析器


7. @Controller 和 @RestController 的区别

@Controller

  • 默认用于返回页面
  • 常配合模板引擎

@RestController

等价于:

  • @Controller
    • @ResponseBody

作用:

方法返回值直接作为响应数据(通常是 JSON)

前后端分离项目的标配。


8. SpringMVC 与 IOC / DI 的关系

关系一定要分清:

  • Controller 对象 → IOC 容器创建
  • Controller 方法调用 → SpringMVC 负责
  • Controller 中的 Service → DI 注入

总结一句话:

IOC 管对象

SpringMVC 管请求

DI 把它们连起来

相关推荐
青云计划8 小时前
知光项目知文发布模块
java·后端·spring·mybatis
赶路人儿8 小时前
Jsoniter(java版本)使用介绍
java·开发语言
Victor3568 小时前
MongoDB(9)什么是MongoDB的副本集(Replica Set)?
后端
Victor3569 小时前
MongoDB(8)什么是聚合(Aggregation)?
后端
探路者继续奋斗9 小时前
IDD意图驱动开发之意图规格说明书
java·规格说明书·开发规范·意图驱动开发·idd
消失的旧时光-194310 小时前
第十九课:为什么要引入消息队列?——异步系统设计思想
java·开发语言
yeyeye11110 小时前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
A懿轩A10 小时前
【Java 基础编程】Java 面向对象入门:类与对象、构造器、this 关键字,小白也能写 OOP
java·开发语言
Tony Bai10 小时前
告别 Flaky Tests:Go 官方拟引入 testing/nettest,重塑内存网络测试标准
开发语言·网络·后端·golang·php
乐观勇敢坚强的老彭10 小时前
c++寒假营day03
java·开发语言·c++