【Spring源码解读!底层原理高级进阶】【上】探寻Spring内部:BeanFactory和ApplicationContext实现原理揭秘✨

 🎉🎉欢迎光临🎉🎉

🏅我是苏泽,一位对技术充满热情的探索者和分享者。🚀🚀

🌟特别推荐给大家我的最新专栏《Spring 狂野之旅:底层原理高级进阶》 🚀

本专栏纯属为爱发电永久免费!!!

这是苏泽的个人主页可以看到我其他的内容哦👇👇

努力的苏泽icon-default.png?t=N7T8http://suzee.blog.csdn.net/

✨这篇文分了三部分来解释Spring--BeanFactory以及ApplicationContext内部的工作原理 本来想一文到底的 奈何太长了...于是拆成了两篇文  

本篇文章的目标,在于通过深入剖析Spring框架的源码,不仅让读者亲身体验到Spring设计大师们的卓越智慧,同时也分享我对其设计哲学所引发的思考与感悟。

如果 觉得阿泽写的还过得去的 观众老爷们可以给个免费的三连 作为一位纯粹的技术热爱者为爱发电的动力🌟

目录

🌼 引言

第一章:Spring框架概览

🌱 Spring框架的设计哲学

在日常工作中的好处

示例

🌿 核心组件与它们的协同工作方式

第二章:深入BeanFactory —— Spring的基石

BeanFactory的角色与职责

定义与类型

核心接口解析

Bean生命周期管理

Bean定义的解析过程

Bean的实例化与依赖注入

初始化与销毁回调

案例分析:BeanFactory如何管理Bean

Spring源码解析

实例化

依赖注入

初始化

测试代码

第三章:ApplicationContext —— 超越BeanFactory

ApplicationContext与BeanFactory的关系

ApplicationContext的核心功能

国际化消息处理

事件发布与监听机制

环境抽象与配置文件管理

实现原理揭秘

如何实现Bean的自动装配

AOP支持的背后机制

🌼 引言

欢迎来到Spring的世界:简介与动机

我很荣幸能与大家一起探索Spring框架的奇妙之处。本文将带领大家从BeanFactory到ApplicationContext,一步步揭示Spring框架的设计原理和核心组件之间的协同工作方式。在这个过程中,我将结合代码和源码解读,以及适当的测试代码来证明观点的正确性。

第一章:Spring框架概览

🌱 Spring框架的设计哲学

Spring框架的设计哲学体现了延迟加载和依赖注入的思想。通过延迟加载,Spring框架可以在应用程序运行时根据需要动态创建和加载Bean,而不是在启动时就创建所有的Bean。这种设计思想有助于提高应用程序的性能和资源利用率。

具体来说,当我们通过BeanFactory获取Bean的时候,Spring框架会检查该Bean是否已经被创建。如果该Bean尚未被创建,Spring框架会按照配置文件中的定义,使用合适的策略来实例化和初始化该Bean。这种延迟加载的设计思想使得应用程序能够更加灵活地管理和使用组件。

在日常工作中的好处

延迟加载和依赖注入的设计思想在日常工作中有许多好处,其中包括:

  1. 提高性能和资源利用率:由于Spring框架延迟加载的特性,只有在需要使用某个Bean时才会进行创建和加载。这可以减少启动时间、内存占用和网络传输等开销,从而提高应用程序的性能和资源利用率。

  2. 降低耦合度:Spring框架的依赖注入机制使得组件之间的依赖关系由外部容器来管理,而不是硬编码在代码中。这样可以降低组件之间的耦合度,使得代码更加灵活、可维护和可测试。

  3. 增强扩展性和可配置性:通过使用Spring框架,我们可以将应用程序的配置信息集中管理,而不是散落在各个组件中。这使得我们可以更方便地进行配置修改和扩展,而无需修改代码。

示例

以下是一个简单的示例,展示了延迟加载和依赖注入在实际业务场景中的提升:

// 示例:订单服务
@Service
public class OrderService {@Autowiredprivate PaymentService paymentService;public void placeOrder() {// 业务逻辑省略// 调用支付服务完成支付paymentService.pay();// 业务逻辑省略}
}// 示例:支付服务
@Service
public class PaymentService {public void pay() {// 执行支付逻辑System.out.println("执行支付逻辑");}
}

在上述示例中,订单服务依赖于支付服务。通过使用Spring框架的依赖注入机制,我们可以将支付服务注入到订单服务中,而无需在订单服务中硬编码创建和管理支付服务的实例。

这样,当订单服务需要使用支付服务时,Spring框架会自动创建和注入支付服务实例。同时,由于延迟加载的特性,支付服务只会在需要时才会被创建和加载。这种设计使得代码更加灵活、可维护和可测试。

🌿 核心组件与它们的协同工作方式

Spring框架的核心组件就像大自然中的各种元素,它们相互配合、相互作用,才能构建出一个完整的生态系统。让我们通过代码和源码解读的方式来展示它们之间的协同工作方式。

// 核心组件的协同工作
public class SpringEcoSystem {public void coordinateWork() {// 创建ApplicationContext对象ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 从ApplicationContext中获取BeanFactoryBeanFactory beanFactory = context.getBeanFactory();// 使用BeanFactory创建和管理BeanComponentA componentA = beanFactory.getBean(ComponentA.class);ComponentB componentB = beanFactory.getBean(ComponentB.class);// 省略其他代码}
}

在上述代码中,我们使用了Spring的ApplicationContext来创建一个应用程序的上下文,并通过它获取了BeanFactory对象。BeanFactory是Spring框架中的一个核心组件,负责创建和管理Bean。

通过源码解读,我们可以发现BeanFactory的设计思想是延迟加载和依赖注入。它在需要使用Bean时才去创建它,而不是在应用程序启动时就创建所有的Bean。这种延迟加载的设计思想可以提高应用程序的性能和资源利用率。

接下来,我们通过测试代码来证明BeanFactory的延迟加载特性:

// 测试BeanFactory的延迟加载特性
public class BeanFactoryLazyLoadingTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");// 获取BeanFactory对象BeanFactory beanFactory = context.getBeanFactory();// 执行一些其他操作for (int i = 0; i < 10000; i++) {System.out.println("test");}// 获取ComponentA对象ComponentA componentA = beanFactory.getBean(ComponentA.class);System.out.println("获取ComponentA对象");// 执行一些其他操作for (int i = 0; i < 10000; i++) {System.out.println("test");}// 获取ComponentB对象ComponentB componentB = beanFactory.getBean(ComponentB.class);System.out.println("获取ComponentB对象");}
}
// 预期结果和执行时间估计
获取ComponentA对象
test
test
test
...
test
获取ComponentB对象

在上述测试代码中,我们先获取了BeanFactory对象,然后执行了一些其他操作。在需要使用ComponentA和ComponentB时,才去通过BeanFactory来获取它们。这样就实现了Bean的延迟加载。

结果是,在执行"获取ComponentA对象"和"获取ComponentB对象"之前,不会创建和加载这两个组件。只有当真正需要使用它们时,才会进行创建和加载。

通过以上的代码和测试,我们可以看到Spring框架中的BeanFactory的设计思想:

延迟加载和依赖注入。

  1. 延迟加载:通过先获取BeanFactory对象,然后执行其他操作的方式,实现了Bean的延迟加载。在需要使用ComponentA和ComponentB时,才去通过BeanFactory来获取它们。这意味着只有在真正需要使用这些组件时,才会进行创建和加载。延迟加载的特性可以提高应用程序的性能和资源利用率。

  2. 依赖注入:通过获取BeanFactory对象,并在需要使用ComponentA和ComponentB时通过BeanFactory来获取它们,实现了依赖注入。在示例中,ComponentA和ComponentB被注入到其他组件中,而不是在代码中硬编码创建和管理它们的实例。这种依赖注入的设计思想降低了组件之间的耦合度,使得代码更加灵活、可维护和可测试。

第二章:深入BeanFactory —— Spring的基石

在Spring框架中,BeanFactory是一个非常核心的接口,它为Spring容器的基础功能提供了定义。BeanFactory可以看作是一个高级的工厂模式实现,负责配置、创建和管理应用程序中的beans。这篇博客将深入探讨BeanFactory的角色、职责和关键实现细节。

BeanFactory的角色与职责

BeanFactory是Spring IoC容器的心脏,IoC(控制反转)是一种设计原则,用于实现依赖注入(DI)。通过BeanFactory,我们可以获得对Spring容器管理的对象(即Beans)的完全控制。它负责:

  • 创建和管理应用程序中的bean
  • 解决bean之间的依赖
  • 管理bean的生命周期
定义与类型

在Spring中,BeanFactory以及其子类如ApplicationContext提供了丰富的功能来支持不同的需求。ApplicationContextBeanFactory的子接口,提供了更多高级特性,如事件发布、国际化支持等。

核心接口解析

BeanFactory提供了几个核心方法,如getBean(String name),用于根据bean的名称获取一个bean实例。此外,containsBean(String name)检查容器中是否包含指定名称的bean。

Bean生命周期管理

Bean的生命周期由创建、初始化、使用到销毁几个阶段组成。BeanFactory负责整个生命周期的管理。其中,初始化和销毁回调是两个重要的生命周期事件。

Bean定义的解析过程

Spring容器启动时,会解析配置文件或注解,构建每个bean定义的BeanDefinition对象。这个过程涉及到读取配置元数据并转换成容器内部结构。

Bean的实例化与依赖注入

Bean的实例化主要有两种方式:构造函数实例化和静态工厂方法实例化。依赖注入(DI)是Spring实现IoC的手段之一,主要有构造器注入和setter方法注入。

初始化与销毁回调

Spring允许在bean的生命周期的特定点执行自定义逻辑,比如通过实现InitializingBeanDisposableBean接口。

案例分析:BeanFactory如何管理Bean

让我们通过一个简单的例子来看看BeanFactory是如何管理Bean的。考虑一个简单的UserService类,我们将展示如何通过XML配置来声明这个Bean,并通过BeanFactory来获取和使用这个Bean。

<bean id="userService" class="com.example.UserService"/>
public class UserService {public void getUser() {System.out.println("Fetching user...");}
}ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.getUser();

预期输出:

Fetching user...

这个例子展示了BeanFactory如何通过配置文件解析、实例化Bean,并进行依赖注入。

Spring源码解析

让我们深入Spring的DefaultListableBeanFactory类,看看Spring是如何实现这些原理的。DefaultListableBeanFactoryBeanFactory接口的一个核心实现类,它管理着容器中的bean定义(BeanDefinition)和bean实例。

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {// 存储bean定义的映射private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);@Overrideprotected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {// 实例化bean的核心逻辑}
}

让我们更深入地探讨DefaultListableBeanFactory类中的createBean方法,以及Spring是如何处理bean的实例化、依赖注入和初始化的。这将帮助我们更好地理解Spring框架的内部工作原理。

实例化

DefaultListableBeanFactory中,实例化bean的过程主要是通过其父类AbstractAutowireCapableBeanFactorycreateBeanInstance方法完成的。这个方法首先会尝试使用构造函数来创建bean实例,如果找到合适的构造函数,它会通过反射来实例化对象。

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {// 确定构造函数并实例化bean
}

在这个过程中,Spring会考虑到构造函数的参数匹配,确保能够找到与配置相匹配的最适合的构造函数进行实例化。

依赖注入

一旦bean被实例化,Spring接下来会进行依赖注入。这一步是通过populateBean方法完成的。在这个方法中,Spring会检查bean定义中的依赖关系,并通过反射来设置bean的属性值或者通过方法注入依赖的对象。

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {// 获取bean的属性值并注入
}

这里,Spring处理了两种类型的依赖注入:基于属性的注入和基于构造函数的注入。对于基于属性的注入,Spring会解析属性值(可能是另一个bean的引用或简单类型的值)并通过setter方法或直接字段访问来注入这些值。对于基于构造函数的注入,这一步骤实际上已经在实例化阶段处理完毕。

初始化

最后,一旦bean被成功实例化并注入所需的依赖,Spring会调用initializeBean方法来处理bean的初始化。这个方法会按顺序执行BeanPostProcessor前置处理、调用自定义的初始化方法(比如实现InitializingBean接口或通过init-method指定的方法),以及BeanPostProcessor后置处理。

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {// 执行BeanPostProcessors的前置处理// 调用bean的初始化方法// 执行BeanPostProcessors的后置处理
}

在这个阶段,Spring提供了强大的扩展点,允许开发者通过实现BeanPostProcessor接口来在bean的初始化前后执行自定义逻辑。

通过以上解析,我们可以看到DefaultListableBeanFactory类中的createBean方法涵盖了bean生命周期的关键阶段:实例化、依赖注入和初始化。每个阶段都有其详细的处理逻辑,保证了bean的正确创建和配置。

测试代码

为了验证我们的理解,我们可以编写一个简单的测试用例来模拟BeanFactory的使用场景。

public class BeanFactoryTest {@Testpublic void testBeanLifecycle() {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");UserService userService = context.getBean("userService", UserService.class);userService.getUser();}
}

预期结果应该与前面的示例相同,显示"Fetching user...",证明我们通过BeanFactory成功地管理了UserService的生命周期。

第三章:ApplicationContext —— 超越BeanFactory

在Spring的世界里,ApplicationContext是一个闪耀的星辰,它不仅继承了BeanFactory的能力,更在此基础上提供了更加丰富和高级的功能。让我们一步步揭开ApplicationContext的神秘面纱,探索它超越BeanFactory的奥秘。

ApplicationContext与BeanFactory的关系

首先,我们需要明确ApplicationContextBeanFactory之间的关系。简单来说,ApplicationContextBeanFactory的子接口,它提供了更加全面的功能。如果说BeanFactory是基础的Spring容器,那么ApplicationContext就是提供了额外增强功能的高级容器。🌱 ➡️ 🌳

ApplicationContext的核心功能

ApplicationContext的核心功能可以说是非常强大,包括但不限于:

  • 国际化消息处理:支持不同语言环境的消息访问和管理。
  • 事件发布与监听机制:允许应用内部各个组件之间进行松耦合的通信。
  • 环境抽象与配置文件管理:提供了一种抽象的方式来处理配置信息,支持不同环境下的配置变更。
国际化消息处理

ApplicationContext中,国际化是通过MessageSource接口来实现的。这使得我们能够很方便地在不同语言环境下获取消息。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
String message = context.getMessage("hello.message", null, Locale.US);
System.out.println(message);

假设我们有一个messages_en_US.properties文件,其中包含以下内容:

hello.message=Hello, World!

上述代码将会输出:

Hello, World!
事件发布与监听机制

ApplicationContext提供了一个基于观察者模式的事件发布与监听机制。这使得应用内部的组件可以发布和监听事件,从而实现松耦合的交互。

public class MyEvent extends ApplicationEvent {public MyEvent(Object source) {super(source);}
}public class MyListener implements ApplicationListener<MyEvent> {@Overridepublic void onApplicationEvent(MyEvent event) {System.out.println("Received event: " + event);}
}ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
context.publishEvent(new MyEvent("Some event"));

这段代码定义了一个自定义事件MyEvent和一个事件监听器MyListener。当事件被发布时,监听器会捕获到这个事件并执行相应的处理逻辑。

环境抽象与配置文件管理

ApplicationContext通过Environment接口提供了一种强大的环境抽象机制,允许我们灵活地管理和访问配置信息。

Environment env = context.getEnvironment();
String property = env.getProperty("some.property");
System.out.println(property);

这使得我们可以根据当前的运行环境(开发、测试、生产等)动态地调整配置信息。

实现原理揭秘

深入到ApplicationContext的实现原理,我们会发现它是通过一系列复杂但精妙的设计模式来实现上述功能的。以事件发布与监听机制为例,其背后是观察者模式的运用。

public class AbstractApplicationContext extends DefaultResourceLoaderimplements ConfigurableApplicationContext {private final ApplicationEventMulticaster applicationEventMulticaster = new SimpleApplicationEventMulticaster();// 其他实现细节...
}

AbstractApplicationContext中持有一个ApplicationEventMulticaster,负责管理事件的发布和监听。当事件发布时,ApplicationEventMulticaster会通知所有注册的监听器。

如何实现Bean的自动装配

ApplicationContext通过@Autowired注解和@ComponentScan注解等提供了强大的自动装配能力。这背后是Spring的依赖注入(DI)机制。

@Component
public class MyComponent {@Autowiredprivate MyDependency dependency;// 类体...
}

Spring容器会自动寻找类型匹配的bean,并注入到MyComponentdependency字段中。

AOP支持的背后机制

最后,ApplicationContext对AOP(面向切面编程)的支持也是其核心功能之一。Spring AOP是通过代理模式实现的,它允许开发者在不修改源码的情况下增强方法的行为。

@Aspect
public class MyAspect {@Before("execution(* com.example.MyComponent.myMethod(..))")public void beforeAdvice(JoinPoint joinPoint) {System.out.println("Before method: " + joinPoint.getSignature().getName());}
}

在这个例子中,MyAspect定义了一个前置通知,它会在MyComponentmyMethod方法执行前被调用。

本文未完待续....

下篇传送门点这里       

下章预告:

第四章:深挖ApplicationContext的高级特性

  • 环境与配置文件的灵活管理
    • Profile的工作原理
    • 使用PropertySources优雅地管理配置
  • 数据访问与事务管理的抽象
    • 数据访问异常的统一处理
    • 声明式事务管理的实现机制

第五章:Spring表达式语言(SpEL)

  • SpEL的设计目的与应用场景
  • SpEL的核心语法与功能
  • 如何通过SpEL实现动态配置

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/675878.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

L1-096 谁管谁叫爹

一、题目 二、解题思路 依据题意判断即可。 三、代码 #include<iostream> using namespace std; #include<cmath> int main() {int n;cin>>n;while(n--){int n1,n2,s10,s20;cin>>n1>>n2;for(int i1;n1/i>0;i*10){s1(n1/i%10);}for(int i1;n…

k8s学习(RKE+k8s+rancher2.x)成长系列之简配版环境搭建(二)

三、简配版集群&#xff0c;适用于demo环境 1.集群架构设计 主机名角色配置(核数&#xff0c;内存&#xff0c;磁盘)MasterRKE,controlplane,etcd,worker,rancher-master2C 8G 40GSlaver1controlplane,worker,rancher-master2C 8G 40GSlaver2controlplane,worker,rancher-mas…

【第三十五节】idea项目的创建以及setting和Project Structure的设置

项目创建 Project Structure的设置 点击file ~ Project Structure 进入 进入view/Appearance 选中Toolbar 就会出现状态栏

# Memory Analyzer (MAT) 在实际开发中的使用

Memory Analyzer (MAT) 在实际开发中的使用 文章目录 Memory Analyzer (MAT) 在实际开发中的使用概述注意点基本使用检查概述获取直方图View the Dominator Tree到GC根的路径 使用示例制作堆dumpHeapDumpOnOutOfMemoryErrorJmap 生成堆Dump Mat打开堆快照HistogramThread Overv…

使用deepspeed继续训练LLAMA

目录 1. 数据训练配置 2. 模型载入 3. 优化器设置 4. DeepSpeed 设置 5. DeepSpeed 初始化 6. 模型训练 LLAMA 模型子结构&#xff1a; 1. 数据训练配置 利用 PyTorch 和 Transformers 库创建数据加载器&#xff0c;它支持单机或多机分布式训练环境下的数据加载与采样。涉…

Uniapp(uni-app)学习与快速上手教程

Uniapp&#xff08;uni-app&#xff09;学习与快速上手教程 1. 简介 Uniapp是一个跨平台的前端框架&#xff0c;允许您使用Vue.js语法开发小程序、H5、安卓和iOS应用。下面是快速上手的步骤。 2. 创建项目 2.1 可视化界面创建 1、打开 HBuilderX&#xff0c;这是一款专为uni…

mysql 中文编码问题

前言 最近在学springboot整合mybatisplus技术&#xff0c;用到mysql数据库&#xff0c;然后发现在windows下插入数据表会出现中文乱码现象 (例如 “我是谁” 在数据库中就成了 “???”) windows show variables like %char%;建表时, 设置默认charset为gbk create table u…

Springboot+vue的社区养老服务平台(有报告)。Javaee项目,springboot vue前后端分离项目

演示视频&#xff1a; Springbootvue的社区养老服务平台&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot vue前后端分离项目 项目介绍&#xff1a; 本文设计了一个基于Springbootvue的前后端分离的社区养老服务平台&#xff0c;采用M&#xff08;model&…

c语言游戏实战(5):走迷宫

前言&#xff1a; 制作一个迷宫游戏是一个有趣的编程挑战。首先&#xff0c;我们需要设计一个二维数组来表示迷宫的布局&#xff0c;其中每个元素代表迷宫中的一个格子。我们可以使用不同的值来表示空格、墙壁和起点/终点。接下来&#xff0c;我们需生成迷宫。在生成迷宫的过程…

自行车 - 骑行前的准备

现在骑自行车的人越来越多了&#xff0c;公路车、山地车、折叠车&#xff0c;有通勤的&#xff0c;也有出来骑游的。为了更好享受骑行带给我们的乐趣&#xff0c;在开始骑行前&#xff0c;你的准备是否充分呢&#xff1f; 最开始&#xff0c;要评估一下天气情况&#xff0c;出车…

最近vscode链接Autodl出现的问题

最近vscode链接Autodl出现的问题 一、问题的概述 在使用vscode连接autodl远程服务器的时候&#xff0c;在vscode的右下角出现了&#xff0c;以下的问题提示&#xff1a; 远程主机可能不符合glibc和libstdc VS Code服务器的先决条件 二、问题的原因 vscode版本过高的问题&…

Redis篇之缓存雪崩

一、什么的缓存雪崩 缓存雪崩&#xff1a;在同一时间段大量的缓存key同时失效或者redis服务宕机&#xff0c;导致大量请求到达数据库给数据库带来巨大压力&#xff0c;可能导致数据库崩了。 二、应该怎么解决 1.给不同的Key的TTL添加随机值 2.利用Redis集群提高服务的可用性 3…

Blender教程(基础)-衰减编辑-20

1、新建一个平面并细分 如下图所示菜单衰减工具 选中一个点上下移动、图形形变衰减 再点击箭头上下移动过程中不要松开鼠标&#xff0c;此时按鼠标中键实现衰减区域的快速调节。 也可以再菜单栏输入参数调节 调节形状 shiftA添加经纬球 按数字1切换正交前视 切换…

GC调优工具

1、jstat 2、VisualVM GC tool插件 插件下载地址&#xff1a;https://blog.csdn.net/jushisi/article/details/109655175 3、Prometheus和Grafana监控

armbian ddns

参考https://mp.weixin.qq.com/s/0Uu_nbGH_W6vAYHPH4kHqg Releases jeessy2/ddns-go GitHub mkdir -p /usr/local/ddns-go cd /usr/local/ddns-gowget https://github.com/jeessy2/ddns-go/releases/download/v6.1.1/ddns-go_6.1.1_freebsd_armv7.tar.gztar zxvf ddns-go_…

新年祝福大家,今年是个好日子,实现100个愿望——早读

神机妙算无人知 引言引言第一篇 人民日报 夜读 今晚&#xff0c;我们想收集100个新年愿望第二篇 新华网 号外&#xff01;新华网联合尔滨、尔佳送新春大大大大礼包啦第三篇&#xff08;跳&#xff09;人民日报 来了新闻早班车要闻社会政策 结尾 引言 昨天回了家 然后我就给我妹…

STM32 cubemx配置DMA+空闲中断接收不定长数据

文章目录 前言一、串口空闲中断二、DMA空闲中断接收不定长数据实现思路三、STM32Cubemx配置DMA空闲中断接收不定长数据四、代码编写总结 前言 本篇文章给大家讲解一下DMA串口空闲中断接收串口不定长数据&#xff0c;之前我们也是讲解过串口接收不定长数据的&#xff0c;那么本…

【Linux】SystemV IPC

进程间通信 一、SystemV 共享内存1. 共享内存原理2. 系统调用接口&#xff08;1&#xff09;创建共享内存&#xff08;2&#xff09;形成 key&#xff08;3&#xff09;测试接口&#xff08;4&#xff09;关联进程&#xff08;5&#xff09;取消关联&#xff08;6&#xff09;释…

CTF--Web安全--SQL注入之‘绕过方法’

一、什么是绕过注入 众所周知&#xff0c;SQL注入是利用源码中的漏洞进行注入的&#xff0c;但是有攻击手段&#xff0c;就会有防御手段。很多题目和网站会在源码中设置反SQL注入的机制。SQL注入中常用的命令&#xff0c;符号&#xff0c;甚至空格&#xff0c;会在反SQL机制中…

Kubernetes - 如何利用 K8S 拉取私有仓库镜像

问题描述 最近实战时&#xff0c;发现一个很奇怪的问题&#xff0c;在通过 k8s 创建 pod&#xff0c;拉取镜像时&#xff0c;总是显示如下信息&#xff1a; Error syncing pod, skipping: failed to "StartContainer" for "POD" with ImagePullBackOff: …