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的角色:作为引导上下文的只读访问接口,它确保注册的组件能够安全、可靠地在应用上下文准备好之前被访问

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

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

相关文章

ELK之路第三步——日志收集筛选logstash和filebeat

logstash和filebeat&#xff08;偷懒版&#xff09; 前言logstash1.下载2.修改配置文件3.测试启动4.文件启动 filebeat1.下载2.配置3.启动 前言 上一篇&#xff0c;我们说到了可视化界面Kibana的安装&#xff0c;这一篇&#xff0c;会简单介绍logstash和filebeat的安装和配置。…

Python毕业设计选题:基于Hadoop的租房数据分析系统的设计与实现

开发语言&#xff1a;Python框架&#xff1a;flaskPython版本&#xff1a;python3.7.7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat11开发软件&#xff1a;PyCharm 系统展示 系统首页 房屋信息详情 个人中心 管理员登录界面 管理员功能界面 用户管理界面 房屋信…

深度学习笔记之BERT(一)BERT的基本认识

深度学习笔记之BERT——BERT的基本认识 引言回顾&#xff1a;Transformer的策略回顾&#xff1a;Word2vec的策略和局限性 BERT \text{BERT} BERT的基本理念抽象的双向BERT的预训练策略 预训练与微调 引言 从本节开始&#xff0c;将介绍 BERT \text{BERT} BERT系列模型以及其常…

YOLOv8改进,YOLOv8引入ResCBAM注意力机制,二次创新C2f结构

摘要 腕部创伤甚至骨折在日常生活中经常发生,在儿童中,他们占骨折病例的很大比例。在进行手术之前,外科医生通常会要求患者先进行 X 光成像,并根据放射科医生的分析进行手术准备。随着神经网络的发展,“You Only Look Once”(YOLO)系列模型在骨折检测中的应用越来越广泛…

CSS--两列网页布局,三列布局和多行多列布局

两列网页布局 两列网页布局实验 先将一个未运用浮动效果的网页结构写出来 <style>header{/* 给页眉设置宽高和样式 */width:1000px;height: 40px;background-color: gray;border: 3px brown solid;margin-bottom: 5px;}article{width:1000px;height: 600px;background-c…

如何使用Web-Check和cpolar实现安全的远程网站监测与管理

文章目录 前言1.关于Web-Check2.功能特点3.安装Docker4.创建并启动Web-Check容器5.本地访问测试6.公网远程访问本地Web-Check7.内网穿透工具安装8.创建远程连接公网地址9.使用固定公网地址远程访问 前言 本期给大家分享一个网站检测工具Web-Check&#xff0c;能帮你全面了解网…

Webserver(2.6)信号

目录 信号的概念信号相关的函数killraiseabortalarm1s钟电脑能数多少个数&#xff1f; setitimer过3s以后&#xff0c;每隔2s定时一次 信号捕捉函数signalsigaction 信号集sigprocmask编写一个程序&#xff0c;把所有的常规信号未决状态打印到屏幕 sigchld信号 信号的概念 比如…

AprilTag在相机标定中的应用简介

1. AprilTag简介 相机标定用的标靶类型多样,常见的形式有棋盘格标靶和圆形标靶。今天要介绍的AprilTag比较特别,它是一种编码形式的标靶。其官网为AprilTag,它是一套视觉基准系统,包含标靶编解码方法(Tag生成)和检测算法(Tag检测),可用于AR、机器人、相机标定等领域。…

Qt报错QOCI driver not loaded且QOCI available的解决方法

参考 Linux Qt 6安装Oracle QOCI SQL Driver插件&#xff08;适用WSL&#xff09; 安装 QOCI 插件完成后运行 Qt 项目报错&#xff1a; qt.sql.qsqldatabase: QSqlDatabase: QOCI driver not loaded qt.sql.qsqldatabase: QSqlDatabase: available drivers: QMIMER QPSQL QODBC…

【MySQL】 穿透学习数据库理论与知识剖析

前言&#xff1a;本节内容讲述一些数据库的基本概念。 第一个部分就是数据库相关的概念&#xff0c; 比如什么是数据库&#xff0c; 如何理解mysqld以及mysql。第二部分理解数据库和表在系统层面的形式。 第三部分就是mysql的一些操作分类。 第四部分就是数据库的插件配置这些。…

Web Broker(Web服务应用程序)入门教程(1)

1、介绍 Web Broker 组件&#xff08;位于工具面板的“Internet”选项卡中&#xff09;可以帮助您创建与特定统一资源标识符&#xff08;URI&#xff09;相关联的事件处理程序。当处理完成后&#xff0c;您可以通过编程方式构建 HTML 或 XML 文档&#xff0c;并将它们传输给客…

网络安全法详细介绍——爬虫教程

目录 [TOC](目录)一、网络安全法详细介绍1. 网络安全法的主要条款与作用2. 网络安全法与爬虫的关系3. 合法使用爬虫的指南 二、爬虫的详细教程1. 准备环境与安装工具2. 使用requests库发送请求3. 解析HTML内容4. 使用robots.txt规范爬虫行为5. 设置请求间隔6. 数据清洗与存储 三…

25国考照片处理器使用流程图解❗

1、打开“国家公务员局”网站&#xff0c;进入2025公务员专题&#xff0c;找到考生考务入口 2、点击下载地址 3、这几个下载链接都可以 4、下载压缩包 5、解压后先看“使用说明”&#xff0c;再找到“照片处理工具”双击。 6、双击后会进入这样的界面&#xff0c;点击&…

Go 语言之搭建通用 Web 项目开发脚手架

Go 语言之搭建通用 Web 项目开发脚手架 MVC 模式 MVC 模式代表 Model-View-Controller&#xff08;模型-视图-控制器&#xff09; 模式。这种模式用于应用程序的分层开发。 Model&#xff08;模型&#xff09; - 模型代表一个存取数据的对象或 JAVA POJO。它也可以带有逻辑&…

江协科技STM32学习- P34 I2C通信外设

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

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

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

【MIT-OS6.S081笔记1】xv6环境搭建

最近开始做一个操作系统的神课MIT-OS6.S081&#xff0c;我做的是老版本的2020版本的&#xff0c;环境使用的是VirtualBox的Ubuntu系统&#xff0c;在这里记录一下学习的过程。首先需要搭建一下环境&#xff0c;参考官网Tools Used in 6.S081&#xff0c;这个知乎文章也写得很好…

深度学习基础—语言模型和序列生成

引言 深度学习基础—循环神经网络&#xff08;RNN&#xff09;https://blog.csdn.net/sniper_fandc/article/details/143417972?fromshareblogdetail&sharetypeblogdetail&sharerId143417972&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 上…

kdd比赛方案

解决方案概述 采用两阶段的方法来解决比赛任务。在第一阶段&#xff0c;采用与 SciBERT 集成的跨编码器模型来确定源论文是否是最重要的参考文献之一。在第二阶段&#xff0c;利用了从目标和源论文中得出的特征&#xff0c;以及第一阶段的输出&#xff0c;输入到几个二进制分类…

抖音Ai图文故事号,AI一键生成故事图片变现,涨粉变现超快!

今天分享2个简单好上手&#xff0c;可批量复制&#xff0c;出单超快的Ai项目&#xff0c;那就是AI绘画壁纸号Ai图文故事号。 在抖音、小红书上&#xff0c;壁纸号火的一塌糊涂&#xff0c;新号3天涨粉1500&#xff0c;变现利润超过了4位数 壁纸看起来平平无奇&#xff0c;市场需…