当前位置: 首页 > news >正文

SpringBoot源码解析(二):启动流程之引导上下文DefaultBootstrapContext

SpringBoot源码系列文章

SpringBoot源码解析(一):启动流程之SpringApplication构造方法

SpringBoot源码解析(二):启动流程之引导上下文DefaultBootstrapContext


目录

  • 前言
  • 一、入口
  • 二、DefaultBootstrapContext
    • 1、BootstrapRegistry接口
    • 2、BootstrapContext接口
    • 3、DefaultBootstrapContext实现类
  • 三、BootstrapRegistryInitializer
    • 1、作用及触发时机
    • 2、示例
  • 总结

前言

  前文深入解析SpringApplication构造方法,而接下来的几篇文章将重点介绍run方法的执行逻辑。

在这里插入图片描述

SpringBoot版本2.7.18的SpringApplication的run方法的执行逻辑如下,本文将详细介绍第一小节:创建引导上下文

// SpringApplication类方法
public ConfigurableApplicationContext run(String... args) {// 记录应用启动的开始时间long startTime = System.nanoTime();// 1.创建引导上下文,用于管理应用启动时的依赖和资源DefaultBootstrapContext bootstrapContext = createBootstrapContext();ConfigurableApplicationContext context = null;// 配置无头模式属性,以支持在无图形环境下运行// 将系统属性 java.awt.headless 设置为 trueconfigureHeadlessProperty();// 2.获取Spring应用启动监听器,用于在应用启动的各个阶段执行自定义逻辑SpringApplicationRunListeners listeners = getRunListeners(args);// 3.发布开始事件、通知ApplicationListener监听器listeners.starting(bootstrapContext, this.mainApplicationClass);try {// 4.解析应用参数ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 5.准备应用环境,包括读取配置文件和设置环境变量ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 配置是否忽略 BeanInfo,以加快启动速度configureIgnoreBeanInfo(environment);// 6.打印启动BannerBanner printedBanner = printBanner(environment);// 7.创建应用程序上下文context = createApplicationContext();// 设置应用启动的上下文,用于监控和管理启动过程context.setApplicationStartup(this.applicationStartup);// 8.准备应用上下文,包括加载配置、添加 Bean 等prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// 9.刷新上下文,完成 Bean 的加载和依赖注入refreshContext(context);// 10.刷新后的一些操作,如事件发布等afterRefresh(context, applicationArguments);// 计算启动应用程序的时间,并记录日志Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}// 11.通知监听器应用启动完成listeners.started(context, timeTakenToStartup);// 12.调用应用程序中的 `CommandLineRunner` 或 `ApplicationRunner`,以便执行自定义的启动逻辑callRunners(context, applicationArguments);}catch (Throwable ex) {// 13.处理启动过程中发生的异常,并通知监听器handleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 14.计算应用启动完成至准备就绪的时间,并通知监听器Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {// 处理准备就绪过程中发生的异常handleRunFailure(context, ex, null);throw new IllegalStateException(ex);}// 返回已启动并准备就绪的应用上下文return context;
}

一、入口

// 1.创建引导上下文,用于管理应用启动时的依赖和资源
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
  • bootstrapRegistryInitializers就是上一篇文章中在SpringApplication构造方法中创建的引导注册组件初始化器集合(查询spring.factories文件,没有找到BootstrapRegistryInitializer的实现类)
  • 调用初始化器的initialize方法,参数为bootstrapContext,也就是说每个初始化器都会对bootstrapContext进行必要的设置和准备(启动时需要的资源和依赖
  • 本方法是在run方法最开始调用的,也就是说引导注册组件初始化器组件的执行时机最早

  主要内容就是实例化DefaultBootstrapContext以及遍历BootstrapRegistryInitializer集合调用initialize,下面详细介绍下这两个类的作用。

// SpringApplication类属性方法// 引导注册初始化器
private List<BootstrapRegistryInitializer> bootstrapRegistryInitializers;private DefaultBootstrapContext createBootstrapContext() {// 创建一个 DefaultBootstrapContext 实例,用于管理应用启动时的资源和依赖DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();// 遍历 bootstrapRegistryInitializers 集合中的每个 initializer,// 并调用它们的 initialize 方法,将 bootstrapContext 作为参数传入。// 这一步确保每个 initializer 都可以对 bootstrapContext 进行相应的配置,// 为应用程序的启动过程准备所需的资源。this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));// 返回已完成初始化的 DefaultBootstrapContext 对象return bootstrapContext;
}

二、DefaultBootstrapContext

  DefaultBootstrapContext作为SpringBoot启动过程中的核心组件,负责环境配置资源管理生命周期管理,确保应用程序的顺利启动和运行。理解其作用有助于开发者更好地掌握SpringBoot的内部机制。

类图如下:

在这里插入图片描述

1、BootstrapRegistry接口

  一个简单的对象注册表,在启动和处理环境配置期间可用,直到ApplicationContext准备好为止。提供对单例的惰性访问,这些单例的创建成本可能很高,或者需要在ApplicationContext可用之前共享。

  注册表使用Class作为键,这意味着只能存储给定类型的单个实例

  addCloseListener(ApplicationListener)方法可用于添加监听器,当BootstrapContext关闭且ApplicationContext已准备好时,该监听器可以执行某些操作。例如,实例可以选择将自身注册为常规SpringBean,以便可供应用程序使用。

public interface BootstrapRegistry {// 注册特定类型到注册表。如果指定的类型已注册且未以单例形式获取,则将替换。<T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier);// 如果尚未存在,则注册特定类型到注册表。<T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier);// 返回给定类型是否已经注册。<T> boolean isRegistered(Class<T> type);// 返回给定类型的已注册 {@link InstanceSupplier},如果没有则返回 null。<T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type);// 添加 {@link ApplicationListener},当 {@link BootstrapContext} 关闭且// {@link ApplicationContext} 准备就绪时,将调用该监听器,并传递 {@link BootstrapContextClosedEvent}。void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener);// 提供所需时创建实际实例的供应者。@FunctionalInterfaceinterface InstanceSupplier<T> {// 工厂方法,在需要时创建实例。T get(BootstrapContext context);// 返回所提供实例的作用域。default Scope getScope() {return Scope.SINGLETON;}// 返回一个具有更新 {@link Scope} 的新 {@link InstanceSupplier}。default InstanceSupplier<T> withScope(Scope scope) {Assert.notNull(scope, "Scope must not be null");InstanceSupplier<T> parent = this;return new InstanceSupplier<T>() {@Overridepublic T get(BootstrapContext context) {return parent.get(context);}@Overridepublic Scope getScope() {return scope;}};}// 工厂方法,用于为给定实例创建 {@link InstanceSupplier}。static <T> InstanceSupplier<T> of(T instance) {return (registry) -> instance;}// 工厂方法,用于从 {@link Supplier} 创建 {@link InstanceSupplier}。static <T> InstanceSupplier<T> from(Supplier<T> supplier) {return (registry) -> (supplier != null) ? supplier.get() : null;}}// 实例的作用域。enum Scope {// 单例实例。 {@link InstanceSupplier} 将仅被调用一次,并且每次都将返回相同的实例。SINGLETON,// 原型实例。 {@link InstanceSupplier} 将在每次需要实例时调用。PROTOTYPE}
}

总结:用于注册引导阶段的组件,在应用启动时通过register方法动态添加对象

2、BootstrapContext接口

  一个简单的引导上下文,在启动和处理环境配置期间可用,直到ApplicationContext准备好为止。提供对单例的惰性访问,这些单例的创建成本可能很高,或者需要在ApplicationContext可用之前共享。

public interface BootstrapContext {// 如果类型已注册,则从上下文中返回实例。如果之前未访问过该实例,则会创建该实例<T> T get(Class<T> type) throws IllegalStateException;// 如果类型已注册,则返回上下文中的实例。如果尚未访问该实例,则将创建它。// 如果类型未注册,则返回指定的替代实例。<T> T getOrElse(Class<T> type, T other);// 如果类型已注册,则返回上下文中的实例。如果尚未访问该实例,则将创建它。// 如果类型未注册,则使用指定的供应者提供的实例。<T> T getOrElseSupply(Class<T> type, Supplier<T> other);// 如果类型已注册,则返回上下文中的实例。如果尚未访问该实例,则将创建它。// 如果类型未注册,则抛出由供应者提供的异常。<T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier) throws X;// 返回给定类型是否存在注册<T> boolean isRegistered(Class<T> type);}

总结:用于提供对引导阶段注册组件的只读访问,一旦BootstrapRegistry注册完成并构建成BootstrapContext,所有组件可以通过get方法被安全地访问,直到应用启动完成。

3、DefaultBootstrapContext实现类

  • ConfigurableBootstrapContext是一个空接口,所以直接看核心内容DefaultBootstrapContext
public interface ConfigurableBootstrapContext extends BootstrapRegistry, BootstrapContext {
}

  DefaultBootstrapContext是一个实现了ConfigurableBootstrapContext接口的类,主要用于管理应用启动过程中的实例供应者实例,提供了注册、获取、关闭监听等功能。以下是主要功能的总结:

  1. 实例供应者管理
    • 使用Map<Class<?>, InstanceSupplier<?>> instanceSuppliers来存储类型到实例供应者的映射,可以通过registerregisterIfAbsent方法来注册实例供应者
    • register方法支持覆盖现有的实例供应者,而registerIfAbsent则仅在类型未注册的情况下注册实例供应者
  2. 实例管理
    • 使用Map<Class<?>, Object> instances存储已创建的实例
    • 提供getgetOrElsegetOrElseSupply等方法来获取实例。如果实例尚未创建,则调用相应的实例供应者来创建实例,并在单例作用域下将其存储
  3. 事件管理(后面文章调用时候细讲)
    • 使用ApplicationEventMulticaster来管理事件的发布和监听
    • 提供addCloseListener方法添加关闭监听器,并在close方法中发布BootstrapContextClosedEvent事件
public class DefaultBootstrapContext implements ConfigurableBootstrapContext {// 存储实例供应者的映射private final Map<Class<?>, InstanceSupplier<?>> instanceSuppliers = new HashMap<>();// 存储已创建实例的映射private final Map<Class<?>, Object> instances = new HashMap<>();// 事件广播器,用于发布应用事件private final ApplicationEventMulticaster events = new SimpleApplicationEventMulticaster();@Overridepublic <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier) {// 注册特定类型的实例供应者register(type, instanceSupplier, true);}@Overridepublic <T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier) {// 如果尚未注册,则注册特定类型的实例供应者register(type, instanceSupplier, false);}private <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier, boolean replaceExisting) {// 检查类型和实例供应者是否为空Assert.notNull(type, "Type must not be null");Assert.notNull(instanceSupplier, "InstanceSupplier must not be null");synchronized (this.instanceSuppliers) {// 检查类型是否已注册boolean alreadyRegistered = this.instanceSuppliers.containsKey(type);if (replaceExisting || !alreadyRegistered) {// 确保实例尚未创建Assert.state(!this.instances.containsKey(type), () -> type.getName() + " has already been created");// 注册实例供应者this.instanceSuppliers.put(type, instanceSupplier);}}}@Overridepublic <T> boolean isRegistered(Class<T> type) {// 检查给定类型是否已注册synchronized (this.instanceSuppliers) {return this.instanceSuppliers.containsKey(type);}}@Override@SuppressWarnings("unchecked")public <T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type) {// 返回已注册的实例供应者synchronized (this.instanceSuppliers) {return (InstanceSupplier<T>) this.instanceSuppliers.get(type);}}@Overridepublic <T> T get(Class<T> type) throws IllegalStateException {// 获取指定类型的实例,如果未注册则抛出异常return getOrElseThrow(type, () -> new IllegalStateException(type.getName() + " has not been registered"));}@Overridepublic <T> T getOrElse(Class<T> type, T other) {// 获取指定类型的实例,如果未注册则返回其他提供的实例return getOrElseSupply(type, () -> other);}@Overridepublic <T> T getOrElseSupply(Class<T> type, Supplier<T> other) {// 尝试获取指定类型的实例,如果未注册则调用其他供应者synchronized (this.instanceSuppliers) {InstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);return (instanceSupplier != null) ? getInstance(type, instanceSupplier) : other.get();}}@Overridepublic <T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier) throws X {// 尝试获取指定类型的实例,如果未注册则抛出由供应者提供的异常synchronized (this.instanceSuppliers) {InstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);if (instanceSupplier == null) {throw exceptionSupplier.get();}return getInstance(type, instanceSupplier);}}@SuppressWarnings("unchecked")private <T> T getInstance(Class<T> type, InstanceSupplier<?> instanceSupplier) {// 获取实例,如果尚未创建则调用实例供应者T instance = (T) this.instances.get(type);if (instance == null) {instance = (T) instanceSupplier.get(this);// 如果作用域为单例,则存储该实例if (instanceSupplier.getScope() == Scope.SINGLETON) {this.instances.put(type, instance);}}return instance;}@Overridepublic void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener) {// 添加关闭监听器,当 BootstrapContext 关闭时触发this.events.addApplicationListener(listener);}/*** 当 {@link BootstrapContext} 关闭且 {@link ApplicationContext} 已准备好时调用的方法。* @param applicationContext 已准备好的上下文*/public void close(ConfigurableApplicationContext applicationContext) {// 发布 BootstrapContext 关闭事件this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));}
}

三、BootstrapRegistryInitializer

1、作用及触发时机

  • 回调接口,用于在BootstrapRegistry(对象注册表)使用之前进行初始化
  • 作用:应用程序启动的早期阶段进行必要的初始化配置
@FunctionalInterface
public interface BootstrapRegistryInitializer {// 此方法在应用启动过程中被调用,允许实现者向注册表注册必要的组件或服务。// 注册的组件随后可以在应用上下文中访问。实现者应仅注册应用所需的类型。void initialize(BootstrapRegistry registry);
}

  引导注册组件初始化器BootstrapRegistryInitializer在SpringApplication的构造方法中通过查找META-INF/spring.factories文件进行加载,然后在引导上下文实例创建完成后,遍历并调用所有BootstrapRegistryInitializer#initialize方法。

在这里插入图片描述

普通SpringBoot项目没有其实现,找了个SpringCloud项目看了下,有两个

在这里插入图片描述

2、示例

自定义BootstrapRegistryInitializer

public class MyBootstrapRegistryInitializer implements BootstrapRegistryInitializer {@Overridepublic void initialize(BootstrapRegistry registry) {// 注册一个自定义服务registry.register(MyCustomService.class, context -> new MyCustomService());System.out.println("MyBootstrapRegistryInitializer已注册");}
}
class MyCustomService {
}

META-INF/spring.factories文件中添加对自定义初始化器的配置

org.springframework.boot.BootstrapRegistryInitializer=com.xc.config.MyBootstrapRegistryInitializer

启动服务

在这里插入图片描述

ps:BootstrapRegistryInitializer是SpringBoot第一个扩展点(注册组件)

总结

  • 引导上下文DefaultBootstrapContext创建:在run方法的最初阶段被实例化,并通过BootstrapRegistryInitializer(第一个注册组件扩展点)进行必要的初始化,确保应用启动时所需的资源和依赖得到妥善管理
  • BootstrapRegistry的作用:该接口作为对象注册表,允许在应用启动早期阶段进行组件的注册和管理,提供了对高成本实例的惰性访问
  • BootstrapContext的角色:作为引导上下文的只读访问接口,它确保注册的组件能够安全、可靠地在应用上下文准备好之前被访问

相关文章:

SpringBoot源码解析(二):启动流程之引导上下文DefaultBootstrapContext

SpringBoot源码系列文章 SpringBoot源码解析(一)&#xff1a;启动流程之SpringApplication构造方法 SpringBoot源码解析(二)&#xff1a;启动流程之引导上下文DefaultBootstrapContext 目录 前言一、入口二、DefaultBootstrapContext1、BootstrapRegistry接口2、BootstrapCon…...

配置elk插件安全访问elk前台页面

编辑els配置文件vim elasticsearch.yml,添加以下配置文件 用elk用户&#xff0c;启动els服务 关闭防火墙&#xff0c;查看els启动是否成功&#xff0c;通过是否启动java进程来判断 或者通过查看是否启动9200和9300端口来判断是否启动 交互模式启动密码配置文件interactive表示交…...

[操作系统作业]页面置换算法实现(C++)

&#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;linux &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &#x1f339;&#x1f339;&#x1f339;关注我带你学习编程知识 目录 必做题代码分析&#xff08;重点以时间统计…...

前端技术月刊-2024.11

本月技术月刊聚焦于前端技术的最新发展和业务实践。业界资讯部分&#xff0c;React Native 0.76 版本发布&#xff0c;带来全新架构&#xff1b;Deno 2.0 和 Node.js 23 版本更新&#xff0c;推动 JavaScript 生态进步&#xff1b;Flutter 团队规模缩减&#xff0c;引发社区关注…...

搜索引擎语法大全(Google、bing、baidu)

搜索引擎语法大全 搜索引擎语法通常指的是在搜索引擎中使用特定的运算符和语法来优化搜索结果。 提高搜索精度&#xff1a;使用特定的语法可以帮助用户更精确地找到相关信息&#xff0c;避免无关结果。例如&#xff0c;通过使用引号搜索确切短语&#xff0c;可以确保搜索结果包…...

java设计模式之行为型模式(11种)

行为型模式 行为型模式用于描述程序在运行时复杂的流程控制&#xff0c;即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务&#xff0c;它涉及算法与对象间职责的分配。 行为型模式分为类行为模式和对象型模式&#xff0c;前者采用继承机制来在类间分派…...

微服务系列一:基础拆分实践

目录 前言 一、认识微服务 1.1 单体架构 VS 微服务架构 1.2 微服务的集大成者&#xff1a;SpringCloud 1.3 微服务拆分原则 1.4 微服务拆分方式 二、微服务拆分入门步骤 &#xff1a;以拆分商品模块为例 三、服务注册订阅与远程调用&#xff1a;以拆分购物车为例 3.1 …...

leetcode 1470.重新排列数组

1.题目要求: 2.题目代码: class Solution { public:vector<int> shuffle(vector<int>& nums, int n) {vector<int> x_array(nums.begin(),nums.begin() n);vector<int> y_array(nums.begin() n,nums.end());int x_index 0;int y_index 0;for…...

windows在两台机器上测试 MySQL 集群实现实时备份

在两台机器上测试 MySQL 集群实现实时备份的基本步骤&#xff1a; 一、环境准备 机器配置 确保两台机器&#xff08;假设为服务器 A 和服务器 B&#xff09;能够互相通信&#xff0c;例如它们在同一个局域网内&#xff0c;并且开放了 MySQL 通信所需的端口&#xff08;默认是 …...

点晴模切ERP系统助力模切企业转型升级之路

随着我国制造业规模不断扩大&#xff0c;中国制造业已经从高速扩张转向深入挖潜的关键阶段。数字化转型不仅有助于提升企业的生产效率和管理水平&#xff0c;还能有效应对市场竞争&#xff0c;实现可持续发展。在数字化转型的过程中&#xff0c;企业资源规划&#xff08;ERP&am…...

redis修改配置文件配置密码开启远程访问后台运行

编辑 Redis 配置文件 编辑 /etc/redis/redis.conf&#xff0c;设置必要的参数。 sudo vim /etc/redis/redis.conf设置后台运行&#xff1a; 找到以下行&#xff0c;将 no 改为 yes&#xff1a; daemonize yes设置密码&#xff1a; 找到以下行&#xff0c;取消注释并设置密码为…...

市场分化!汽车零部件「变天」

全球汽车市场的动荡不安&#xff0c;还在持续。 本周&#xff0c;全球TOP20汽车零部件公司—安波福&#xff08;Aptiv&#xff09;发布2024年第三季度财报显示&#xff0c;三季度公司经调整后确认收入同比下降6%&#xff1b;按照区域市场来看&#xff0c;也几乎是清一色的下滑景…...

SCSS在Vue中的用法

SCSS在Vue中的用法 一、安装相关依赖1、安装sass - loader和node - sass&#xff08;或dart - sass&#xff09; 二、在组件中使用SCSS1、单文件组件&#xff08;.vue&#xff09;中的样式使用2、**全局样式使用SCSS**3、在组件中使用变量和混入&#xff08;Mixins&#xff09;…...

CPU用户时间百分比

在计算机系统中&#xff0c;"CPU用户时间百分比&#xff08;CPU User Time&#xff09;"是一个性能监控指标&#xff0c;它描述了CPU在用户模式下执行的累积时间与总的CPU时间的比例。这个指标可以帮助我们了解系统在执行用户态程序时的负载情况。下面是一些关于CPU用…...

RN中的StyleSheet

一、RN中样式的特点 RN的样式和前端的CSS的样式有一些区别。主要如下&#xff1a; RN中的样式 前端的CSS 继承性 没有继承性 有继承性 命名 fontSize&#xff08;小驼峰命名&#xff09; font-size 尺寸单位 with: 100 With: 100px 特殊的样式名 marginHorizontal…...

Swift 开发教程系列 - 第1章:Swift 简介与开发环境配置

在开始开发 Swift 应用之前&#xff0c;了解 Swift 语言的背景和设置开发环境非常重要。接下来&#xff0c;我们将逐步介绍 Swift 的基本概念&#xff0c;并带你完成开发环境的安装和项目创建。 1.1 Swift 简介 Swift 是由 Apple 开发的一种现代化编程语言&#xff0c;于 201…...

躺平成长-下一个更新的数据(躺平成长数据显示核心)

旭日图&#xff08;Sunburst Chart&#xff09;是一种用于展示具有层次结构数据的可视化图表。 开源竞争&#xff1a; &#xff08;当你无法掌握技术的时候&#xff0c;就开源这个技术&#xff0c;培养出更多的技术依赖&#xff0c;让更多的人帮助你完善你的技术&#xff0c;那…...

你们接口怎么测?有没有完完整整的把一个接口测下来?

面试官在问到这道问题的时候&#xff0c;我们应该这么去回答&#xff0c;根据自己技术掌握的水准进行由浅入深的回答。 基础&#xff1a; 我们接口测试之前&#xff0c;开发都会有一份接口文档给到我们&#xff0c;我们要分析接口中的入参和响应。 针对入参的参数类型和参数…...

Pinia-状态管理

Pinia-状态管理 特点&#xff1a; 1. 轻量和模块化 Pinia 是一个轻量级的状态管理库&#xff0c;支持模块化管理&#xff0c;即可以将应用的状态分成多个 store 以实现更好的组织。使用 Pinia&#xff0c;可以定义多个 store&#xff0c;每个 store 都是一个独立的模块&#x…...

IP系列之bscan讨论

1、做Bcan前首先要确定ip_vender是否已经在phy_level做好了bscan_chian&#xff1f;&#xff1f;&#xff1f; 若已经做好&#xff0c;那么vender会给一个XXX.bsdl文件&#xff0c;结合详细的ip文档指导手册&#xff0c;确定bscan_chain是在内部的tap下挂着&#xff0c;还是单…...

Centos安装配置Jenkins

下载安装 注意&#xff1a;推荐的LTS版本对部分插件不适配&#xff0c;直接用最新的版本&#xff0c;jenkins还需要用到git和maven&#xff0c;服务器上已经安装&#xff0c;可查看参考文档[1]、[2]&#xff0c;本次不再演示 访问开始使用 Jenkins 下载jenkins 上传至服务器…...

创新医疗突破:新型穿刺器显著提高手术安全性与效率

据QYResearch调研团队最新报告“中国穿刺器市场报告2023-2029”显示&#xff0c;预计2029年中国穿刺器市场规模将达到18.5亿美元&#xff0c;未来几年年复合增长率CAGR为18.1%。 如上图表/数据&#xff0c;摘自QYResearch最新报告“中国穿刺器市场研究报告2023-2029. 如上图表/…...

【MySQL】可重复读级别下基于Next Key Lock解决幻读

昨天读到了一篇文章[1]&#xff0c;里面讲&#xff0c;面试官说mysql的可重复读级别下有解决幻读的方式&#xff0c;最后公布了答案&#xff0c;是在sql后面加for update。这么说倒是没错&#xff0c;但是这种问法给我一种奇怪的感觉&#xff0c;因为for update无论在哪个隔离级…...

【安全性分析】正式安全分析与非正式安全分析

安全性分析-系列文章目录 第一章 【安全性分析】正式安全分析与非正式安全分析 第二章 【安全性分析】BAN逻辑 (BAN Logic) 文章目录 安全性分析-系列文章目录前言一、正式安全分析1. 理想化模型(如随机预言机模型)2. 标准模型(Standard Model)3. 形式化验证4. 数学证明二…...

【项目开发】高校思政课程实践任务平台—数据库设计

未经许可,不得转载。 文章目录 1、项目需求2、数据库选型3、概念数据模型设计3.1、实体及属性3.2、实体关系3.3、补充说明4、数据库语句4.1、数据库对象创建语句4.2、功能实现的SQL语句4.3、视图创建语句4.4、触发器创建语句5、安全性考虑5.1、用户认证和授权5.2、数据传输安全…...

计算机网络安全应该学习哪些知识?

计算机网络安全是一个广泛而深入的领域&#xff0c;要成为一名专业的网络安全专家&#xff0c;需要系统地学习多个方面的知识。以下是一些关键的学习方向&#xff1a; 一、基础知识计算机网络&#xff1a;学习OSI、TCP/IP模型&#xff0c;网络协议&#xff0c;网络设备工作原理…...

logrotate工具强制日志轮询

说明: 1、通过定时任务logrotate工具每天强制日志轮询并压缩,节省存储空间。 参数说明: 1)/opt/yolov5/logs/.log: 是指要轮转日志文件的路径和名称。 是一个通配符,表示匹配以*.log结尾文件名。 2)daily: 是指日志文件每天轮转一次。 3)dateext: 是指轮转的日志文件名中…...

微服务系列三:微服务核心——网关路由

目录 前言 一、登录存在的问题归纳 二、*微服务网关整体方案 三、认识微服务网关 四、网关鉴权实现 五、OpenFeign微服务间用户标识信息传递实现 六、微服务网关知识追问巩固 前言 本篇文章具体讲解微服务中网关的实现逻辑、用于解决什么样的问题。其中标题中标注* 涉…...

【系统架构设计师】2023年真题论文: 论边云协同的设计与实现(包括解题思路和素材)

更多内容请见: 备考系统架构设计师-专栏介绍和目录 文章目录 真题题目(2023年 试题4)解题思路边云协同概念和架构边云协同的关键技术边云协同的设计与实现案例分析论文素材参考真题题目(2023年 试题4) 边云协同是指将边缘计算和云计算相结合,实现边缘设备与云端资源之间…...

vue3记录(第一版)

vue2与vue3的区别 vue2属于选项式API,vue3属于组合式API setup概述 setup是vue3中一个新的配置项,值是一个函数,组件中所用到的数据,方法,计算属性,监视等等,均配置在setup中 vue3中的setup和vue2的data,methods之间有什么关系呢? 因为setup比data解析的早,所以在data中可以…...