SpringBoot3.X源码分析(启动流程)

@SpringBootApplication(
    scanBasePackages = {"com.javaedge.base"}
)
public class BaseApplication {
    public BaseApplication() {
    }

    public static void main(String[] args) {
        SpringApplication.run(BaseApplication.class, args);
    }
}

1 启动入口

静态辅助类,可用于运行使用默认配置(即我们添加的一系列注解)的指定源的 SpringApplication 。

  • primarySource - 要载入的主要源,即指定源,这里为传入的Application.class Class\<?> :泛型决定了任何类都可以传入
  • args - 应用程序参数(通常从main方法传递)
  • 返回:正在运行的ApplicationContext
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  return run(new Class<?>[] { primarySource }, args);
}
  • 1.
  • 2.
  • 3.
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  return new SpringApplication(primarySources).run(args);
}
  • 1.
  • 2.
  • 3.

构造一个SpringApplication的实例,然后再调用这里实例的run方法就表示启动SpringBoot。因此,想要分析SpringBoot的启动过程,我们需要熟悉:

  • SpringApplication的构造过程
  • SpringApplication的run方法执行过程

2 SpringApplication的构造过程

创建新 SpringApplication 实例。应用程序上下文将从指定的主要源加载 bean。实例可以在调用 run(String...)之前自定义。

public SpringApplication(Class<?>... primarySources) {
		this(null, primarySources);
	}
@SuppressWarnings({ "unchecked", "rawtypes" })
	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    
    // 判断是否是web程序:
    // jakarta.servlet.Servlet
    // org.springframework.web.context.ConfigurableWebApplicationContext
    // 须都在类加载器中存在,并设置到webEnvironment属性
		this.webApplicationType = WebApplicationType.deduceFromClasspath();

    // 从 META-INF/spring.factories 中找K=ApplicationContextInitializer的类并实例化后
    // 设置到SpringApplication的initializers属性。即找出所有的应用程序初始化器
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));

    // 从spring.factories文件中找出key为ApplicationListener的类并实例化后
    // 设置到SpringApplication的listeners属性。即找出所有的应用程序事件监听器
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    // 找出main类,这里是 BaseApplication 类
		this.mainApplicationClass = deduceMainApplicationClass();
	}
ApplicationContextInitializer

可能是全网最全的SpringBoot启动流程源码分析(最新3.x版本)_spring

应用程序初始化器,做一些初始化的工作。

用于在刷新之前初始化 Spring ConfigurableApplicationContext 的回调接口。 通常用于需要对应用程序上下文进行某种编程初始化的 Web 应用程序中。如针对上下文的环境注册属性源或激活配置文件。

ApplicationContextInitializer 鼓励处理器检测 Spring 的 Ordered 接口是否已实现或 @Order 注解是否存在,并在调用之前对实例进行相应的排序(如果有)

@FunctionalInterface
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {

	/**
	 * Initialize the given application context.
	 * @param applicationContext the application to configure
	 */
	void initialize(C applicationContext);

}
ApplicationListener

可能是全网最全的SpringBoot启动流程源码分析(最新3.x版本)_bootstrap_02

ApplicationEvent监听器:

@FunctionalInterface
public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {

	void onApplicationEvent(E event);

	static <T> ApplicationListener<PayloadApplicationEvent<T>> forPayload(Consumer<T> consumer) {
		return event -> consumer.accept(event.getPayload());
	}

}
SpringApplicationEvent

可能是全网最全的SpringBoot启动流程源码分析(最新3.x版本)_bootstrap_03

应用程序的:

  • 启动事件,ApplicationStartingEvent。一旦一个 SpringApplication 开始,事件就会尽早发布 - 在 or ApplicationContext 可用之前Environment,但在注册之后ApplicationListener。事件的来源是本身SpringApplication,但要注意不要在这个早期阶段过多地使用其内部状态,因为它可能会在生命周期的后期被修改
  • 失败事件,ApplicationFailedEvent
  • 准备事件,ApplicationPreparedEvent 事件发布为 当一个SpringApplication正在启动并且ApplicationContext已完全准备好但未refresh。将加载 Bean 定义,并在此阶段可以使用
  • ApplicationEnvironmentPreparedEvent
  • ContextClosedEvent

应用程序事件监听器跟监听事件是绑定的,如:

  • ConfigServerBootstrapApplicationListener只跟ApplicationEnvironmentPreparedEvent事件绑定
  • LiquibaseServiceLocatorApplicationListener只跟ApplicationStartedEvent事件绑定
  • LoggingApplicationListener跟所有事件绑定

3 SpringApplication的执行

先看一些事件和监听器概念:

  • SpringApplicationRunListeners类
  • SpringApplicationRunListener类
3.1 SpringApplicationRunListeners

用于监听SpringApplication的run方法的执行。用于SpringApplicationRunListener监听器的批量执行。

finish:run方法结束之前调用;对应事件的类型是ApplicationReadyEvent或ApplicationFailedEvent

class SpringApplicationRunListeners {

  // Log日志类
	private final Log log;

  // 持有SpringApplicationRunListener集合
	private final List<SpringApplicationRunListener> listeners;

	private final ApplicationStartup applicationStartup;

  // run方法执行时立马执行;对应事件类型ApplicationStartingEvent
	void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
		doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
				(step) -> {
					if (mainApplicationClass != null) {
						step.tag("mainApplicationClass", mainApplicationClass.getName());
					}
				});
	}

  // ApplicationContext创建之前并且环境信息准备好的时候调用;对应事件类型ApplicationEnvironmentPreparedEvent
	void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
		doWithListeners("spring.boot.application.environment-prepared",
				(listener) -> listener.environmentPrepared(bootstrapContext, environment));
	}

  // ApplicationContext创建好并且在source加载之前调用一次;没有具体的对应事件
	void contextPrepared(ConfigurableApplicationContext context) {
		doWithListeners("spring.boot.application.context-prepared", (listener) -> listener.contextPrepared(context));
	}

  // ApplicationContext创建并加载之后,并在refresh之前调用
  // 对应事件类型ApplicationPreparedEvent
	void contextLoaded(ConfigurableApplicationContext context) {
		doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
	}


	void started(ConfigurableApplicationContext context, Duration timeTaken) {
		doWithListeners("spring.boot.application.started", (listener) -> listener.started(context, timeTaken));
	}

	void ready(ConfigurableApplicationContext context, Duration timeTaken) {
		doWithListeners("spring.boot.application.ready", (listener) -> listener.ready(context, timeTaken));
	}

	void failed(ConfigurableApplicationContext context, Throwable exception) {
		doWithListeners("spring.boot.application.failed",
				(listener) -> callFailedListener(listener, context, exception), (step) -> {
					step.tag("exception", exception.getClass().toString());
					step.tag("message", exception.getMessage());
				});
	}

	private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
			Throwable exception) {
		try {
			listener.failed(context, exception);
		}
		catch (Throwable ex) {
			if (exception == null) {
				ReflectionUtils.rethrowRuntimeException(ex);
			}
			if (this.log.isDebugEnabled()) {
				this.log.error("Error handling failed", ex);
			}
			else {
				String message = ex.getMessage();
				message = (message != null) ? message : "no error message";
				this.log.warn("Error handling failed (" + message + ")");
			}
		}
	}

	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
		doWithListeners(stepName, listenerAction, null);
	}

	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
			Consumer<StartupStep> stepAction) {
		StartupStep step = this.applicationStartup.start(stepName);
		this.listeners.forEach(listenerAction);
		if (stepAction != null) {
			stepAction.accept(step);
		}
		step.end();
	}

}

SpringApplicationRunListener目前只有一个实现类EventPublishingRunListener:

可能是全网最全的SpringBoot启动流程源码分析(最新3.x版本)_应用程序_04

/**
 * SpringApplicationRunListener to publish SpringApplicationEvents.
 * Uses an internal ApplicationEventMulticaster for the events that are fired
 * before the context is actually refreshed.
 */
class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

	private final SpringApplication application;

	private final String[] args;

	private final SimpleApplicationEventMulticaster initialMulticaster;

	@Override
	public void starting(ConfigurableBootstrapContext bootstrapContext) {
		multicastInitialEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
	}

	@Override
	public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
			ConfigurableEnvironment environment) {
		multicastInitialEvent(
				new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
	}

	@Override
	public void contextPrepared(ConfigurableApplicationContext context) {
		multicastInitialEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
	}

	@Override
	public void contextLoaded(ConfigurableApplicationContext context) {
		for (ApplicationListener<?> listener : this.application.getListeners()) {
			if (listener instanceof ApplicationContextAware contextAware) {
				contextAware.setApplicationContext(context);
			}
			context.addApplicationListener(listener);
		}
		multicastInitialEvent(new ApplicationPreparedEvent(this.application, this.args, context));
	}

	@Override
	public void started(ConfigurableApplicationContext context, Duration timeTaken) {
		context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
		AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
	}

	@Override
	public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
		context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
		AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
	}

	@Override
	public void failed(ConfigurableApplicationContext context, Throwable exception) {
		ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
		if (context != null && context.isActive()) {
			// Listeners have been registered to the application context so we should
			// use it at this point if we can
			context.publishEvent(event);
		}
		else {
			// An inactive context may not have a multicaster so we use our multicaster to
			// call all the context's listeners instead
			if (context instanceof AbstractApplicationContext abstractApplicationContext) {
				for (ApplicationListener<?> listener : abstractApplicationContext.getApplicationListeners()) {
					this.initialMulticaster.addApplicationListener(listener);
				}
			}
			this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
			this.initialMulticaster.multicastEvent(event);
		}
	}

  // 广播事件出去
	private void multicastInitialEvent(ApplicationEvent event) {
		refreshApplicationListeners();
		this.initialMulticaster.multicastEvent(event);
	}

	private void refreshApplicationListeners() {
		this.application.getListeners().forEach(this.initialMulticaster::addApplicationListener);
	}

	private static class LoggingErrorHandler implements ErrorHandler {

		private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);

		@Override
		public void handleError(Throwable throwable) {
			logger.warn("Error calling ApplicationEventListener", throwable);
		}

	}

}

它把监听过程封装成SpringApplicationEvent事件,并让内部属性initialMulticaster,ApplicationEventMulticaster接口的实现类SimpleApplicationEventMulticaster广播出去:

可能是全网最全的SpringBoot启动流程源码分析(最新3.x版本)_应用程序_05

广播出去的事件对象会被SpringApplication中的listeners属性进行处理。

可能是全网最全的SpringBoot启动流程源码分析(最新3.x版本)_bootstrap_06

所以SpringApplicationRunListener和ApplicationListener之间的关系是通过ApplicationEventMulticaster广播出去的SpringApplicationEvent所联系。

可能是全网最全的SpringBoot启动流程源码分析(最新3.x版本)_应用程序_07

创建所有 Spring 运行监听器并发布应用启动事件

调用getSpringFactoriesInstances 获取配置的监听器名称,并实例化所有的类。

SpringApplicationRunListener所有监听器配置在 pring.factories :

可能是全网最全的SpringBoot启动流程源码分析(最新3.x版本)_spring_08

3.2 run
public ConfigurableApplicationContext run(String... args) {
    // 开始执行,记录开始时间
		long startTime = System.nanoTime();
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		ConfigurableApplicationContext context = null;
    // 设置系统属性 java.awt.headless 的值,默认为true
		configureHeadlessProperty();
    
    // 获取SpringApplicationRunListeners,内部只有一个EventPublishingRunListener
    // 创建所有 Spring 运行监听器并发布应用启动事件
		SpringApplicationRunListeners listeners = getRunListeners(args);
    
    // 会封装成SpringApplicationEvent事件然后广播出去给SpringApplication中的listeners所监听
    // 这里接受ApplicationStartedEvent事件的listener会执行相应操作
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
      // 初始化默认应用参数类
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      
      // 根据运行监听器和应用参数来准备 Spring 环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			Banner printedBanner = printBanner(environment);
      
      // 创建Spring容器,即创建应用上下文
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
     // 准备应用上下文
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			refreshContext(context);
      
      // 容器创建完成之后执行额外一些操作
			afterRefresh(context, applicationArguments);
			Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
			}
      // 广播出ApplicationReadyEvent事件给相应的监听器执行
      // 发布应用上下文启动完成事件
			listeners.started(context, timeTakenToStartup);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			if (ex instanceof AbandonedRunException) {
				throw ex;
			}
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			if (context.isRunning()) {
				Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
        // 发布应用上下文就绪事件
				listeners.ready(context, timeTakenToReady);
			}
		}
		catch (Throwable ex) {
			if (ex instanceof AbandonedRunException) {
				throw ex;
			}
      // 过程报错的话会执行一些异常操作
      // 然后广播出ApplicationFailedEvent事件给相应的监听器执行
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
    // 返回Spring容器
		return context;
	}
设置系统属性 java.awt.headless 的值
private void configureHeadlessProperty() {
  System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS,
      System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless)));
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【从0上手cornerstone3D】如何渲染一个基础的Dicom文件(含演示)

一、Cornerstone3D 是什么&#xff1f; Cornerstone3D官网&#xff1a;https://www.cornerstonejs.org/ 在线查看显示效果&#xff08;加载需时间&#xff0c;可先点击运行&#xff09;&#xff0c;欢迎fork 二、代码示例 了解了Cornerstone是什么&#xff0c;有什么作用后&…

SpringBoot3自动配置原理

​​​​​​自动配置 遵循约定大约配置的原则&#xff0c;在boot程序启动后&#xff0c;起步依赖中的一些bean对象会自动注入到ioc容器 看一下我们前面写的代码有没有达到自动配置的效果呢&#xff1f; 没有自动&#xff0c;我们写了配置类&#xff0c;写了Import注解&#…

解释程序基本原理

解释程序基本原理 1、解释程序的基本结构2、高级语言编译与解释方式的比较 语言处理程序是一类系统软件的总称&#xff0c;其主要作用是将高级语言或汇编语言编写的程序翻译成某种机器语言程序&#xff0c;使程序可在计算机上运行。语言处理程序主要分为汇编程序、编译程序和解…

匠心科技BLDC开发板原理图讲解

匠心科技BLDC开发板资料 链接&#xff1a;https://pan.baidu.com/s/1s5YjzRSDLKQvl86lBVAqKA?pwda6cx 提取码&#xff1a;a6cx 解压密码&#xff1a;JXKJ_RALDNWB站视频讲解&#xff08;&#xff09; 链接: 匠心科技直流无刷电机开发板原理图讲解 BLDC的开发板主要分为四个模…

Docker登录MySQL,密码正确却提示密码错误

当我输入了正确的MySQL密码的时候确提示我密码错误&#xff1a; ERROR 1045 (28000): Access denied for user rootlocalhost (using password: YES) docker run --name mysql_master \ -e MYSQL_ROOT_PASSWORD123123 \ -v /root/mysql_master/data:/var/lib/mysql \ -v /root…

Vulnhub-GoldenEye

一、信息收集 nmap探测&#xff1a;nmap -p 1-65535 -T4 -A -v 192.168.1.9 PORT STATE SERVICE VERSION 25/tcp open smtp Postfix smtpd |_smtp-commands: ubuntu, PIPELINING, SIZE 10240000, VRFY, ETRN, STARTTLS, ENHANCEDSTATUSCODES, 8BITMIME, DSN |_…

【Git】本地仓库文件的创建、修改和删除

目录 一、基本信息设置 1、设置用户名2、设置用户名邮箱 二、Git仓库操作介绍 1、创建一个新的文件夹2、在文件内初始化git仓库&#xff08;创建git仓库&#xff09;3、向仓库中添加文件 1.创建一个文件2.将文件添加到暂存区3.将暂存区添加到仓库 4、修改仓库文件 1.修改文件2.…

imgaug库指南(20):从入门到精通的【图像增强】之旅

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

紫光展锐T770安卓核心板_展锐T770 5G核心板规格参数

紫光展锐T770安卓核心板是一款高性能的5G安卓智能模块&#xff0c;拥有先进的6nm制程工艺和强大的性能。板载8GB Ram 256GBROM的内存单元&#xff0c;支持4K H.265/ H.264视频编解码&#xff0c;搭载Android 13以上操作系统&#xff0c;功能丰富。除了支持5G NSA和SA双模式向下…

大数据赋能电竞出海企业发展

近几年电竞行业发展迅速&#xff0c;我国单2022年新增近4万家电竞相关企业&#xff0c;竞争十分激烈。中国电竞市场规模在全球占比19%左右&#xff0c;海外有巨大的增量市场&#xff0c;特别是东南亚、中南亚和拉丁美洲是电竞市场增长最快的地区&#xff0c;在2020至2025年期间…

Hive基础知识(十二):Hive的基本查询

1. 全表和特定列查询 0&#xff09;数据准备 原始数据 dept: 10 ACCOUNTING 1700 20 RESEARCH 1800 30 SALES 1900 40 OPERATIONS 1700 emp&#xff1a; 7369 SMITH CLERK 7902 1980-12-17 800.00 20 7499 ALLEN SALESMAN 7698 1981-2-20 1600.00 300.00 30 7521 WARD SALESM…

【如何使用iPad通过Code App+cpolar实现公网地址远程访问vscode】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 1. 在iPad下载Code APP2.安装cpolar内网穿透2.1 cpolar 安装2.2 创建TCP隧道 3. iPad远程vscode4. …

Pytorch的默认初始化分布 nn.Embedding.weight初始化分布

一、nn.Embedding.weight初始化分布 nn.Embedding.weight随机初始化方式是标准正态分布 &#xff0c;即均值$\mu0$&#xff0c;方差$\sigma1$的正态分布。 论据1——查看源代码 ## class Embedding具体实现&#xff08;在此只展示部分代码&#xff09; import torch from t…

如何在 SwiftUI 中实现音频图表

文章目录 前言DataPoint 结构体BarChartView 结构体ContentView 结构体实现协议实现线图总结 前言 在可访问性方面&#xff0c;图表是复杂的事物之一。iOS 15 引入了一项名为“音频图表”的新功能。 下面我们将学习如何通过使用 accessibilityChartDescriptor 视图修饰符为任…

数据结构与算法教程,数据结构C语言版教程!(第三部分、栈(Stack)和队列(Queue)详解)五

第三部分、栈(Stack)和队列(Queue)详解 栈和队列&#xff0c;严格意义上来说&#xff0c;也属于线性表&#xff0c;因为它们也都用于存储逻辑关系为 "一对一" 的数据&#xff0c;但由于它们比较特殊&#xff0c;因此将其单独作为一章&#xff0c;做重点讲解。 使用栈…

Histone H3K4me2 Antibody, SNAP-Certified™ for CUTRUN

EpiCypher是一家为表观遗传学和染色质生物学研究提供高质量试剂和工具的专业制造商。EpiCypher推出的CUT&RUN级别的Histone H3K4me2 Antibody符合EpiCypher的批次特异性SNAP-CertifiedTM标准&#xff0c;在CUT&RUN中具有特异性和高效的靶点富集。通过SNAP-CUTANA™K-Me…

智能分析网关V4基于AI视频智能分析技术的周界安全防范方案

一、背景分析 随着科技的不断进步&#xff0c;AI视频智能检测技术已经成为周界安全防范的一种重要手段。A智能分析网关V4基于深度学习和计算机视觉技术&#xff0c;可以通过多种AI周界防范算法&#xff0c;实时、精准地监测人员入侵行为&#xff0c;及时发现异常情况并发出警报…

LeetCode - 1371 每个元音包含偶数次的最长子字符串(Java JS Python C)

题目来源 1371. 每个元音包含偶数次的最长子字符串 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你一个字符串 s &#xff0c;请你返回满足以下条件的最长子字符串的长度&#xff1a;每个元音字母&#xff0c;即 a&#xff0c;e&#xff0c;i&#xff0c;o&#xff0…

DrGraph原理示教 - OpenCV 4 功能 - 边界填充

今天简单来看一下OpenCV中的边界填充 param src Source image. param dst Destination image of the same type as src and the size Size(src.colsleftright, src.rowstopbottom) . param top the top pixels param bottom the bottom pixels param left the left pixels par…

Redis-浅谈redis.conf配置文件

Redis.conf Redis.conf是Redis的配置文件&#xff0c;它包含了一系列用于配置Redis服务器行为和功能的选项。 以下是Redis.conf中常见的一些选项配置&#xff1a; bind: 指定Redis服务器监听的IP地址&#xff0c;默认为127.0.0.1&#xff0c;表示只能本地访问&#xff0c;可以…