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

Spring Boot应用中实现Jar包热更新的实践指南

Spring Boot应用中实现Jar包热更新的实践指南

一、引言

在现代软件开发中,快速迭代和持续交付是至关重要的。对于基于Spring Boot的应用程序,一旦部署到生产环境,传统的更新方式通常是重新打包并重启应用,这不仅耗时,还可能导致服务中断。为了提高开发效率并减少对用户的影响,实现Jar包的热更新成为一种理想的选择。本文将详细介绍如何在Spring Boot应用中实现Jar包的热更新,包括核心思路、代码实现以及注意事项。

二、热更新的核心思路

(一)基于JVM类加载器

Java的类加载机制允许在运行时动态加载新的类。通过自定义类加载器,我们可以实现对指定Jar包的加载和卸载,而无需重启整个应用。这是实现热更新的关键技术基础。

(二)Spring Bean动态注册

Spring Boot应用的核心是Spring容器,它管理着应用中的各种Bean。为了使新加载的Jar包中的类能够被Spring容器识别和管理,我们需要动态地将这些类注册为Spring Bean,并确保它们能够正确地与其他Bean进行依赖注入。

(三)文件监听与上传

为了实现热更新,我们需要一个机制来检测新的Jar包文件是否被上传到指定目录,并触发加载或更新流程。这可以通过监听文件系统的变化来实现,也可以通过提供一个文件上传接口来手动触发。

三、实现步骤

(一)创建自定义类加载器

我们需要创建一个自定义的类加载器,用于加载指定目录下的Jar包。以下是HotClassLoader的实现代码:

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;public class HotClassLoader extends URLClassLoader {private static final Map<String, Long> jarLastModifiedMap = new HashMap<>();public HotClassLoader(URL[] urls, ClassLoader parent) {super(urls, parent);}public static synchronized void loadJar(String jarPath) throws IOException {File jarFile = new File(jarPath);if (!jarFile.exists()) {throw new IOException("Jar file does not exist: " + jarPath);}long lastModified = jarFile.lastModified();if (jarLastModifiedMap.containsKey(jarPath) && jarLastModifiedMap.get(jarPath) == lastModified) {System.out.println("Jar file has not changed: " + jarPath);return;}URL url = jarFile.toURI().toURL();URLClassLoader loader = new HotClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());jarLastModifiedMap.put(jarPath, lastModified);System.out.println("Loaded jar: " + jarPath);}public static synchronized void unloadJar(String jarPath) {if (!jarLastModifiedMap.containsKey(jarPath)) {System.out.println("Jar file is not loaded: " + jarPath);return;}jarLastModifiedMap.remove(jarPath);System.out.println("Unloaded jar: " + jarPath);}
}

(二)动态加载Jar包

我们需要编写代码来扫描指定目录下的Jar包,并使用HotClassLoader加载它们。以下是JarLoader类的实现:

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;public class JarLoader {private static final String PLUGIN_DIR = "plugins/";public static void loadJars() throws IOException {File pluginDir = new File(PLUGIN_DIR);if (!pluginDir.exists()) {pluginDir.mkdirs();}File[] jarFiles = pluginDir.listFiles((dir, name) -> name.endsWith(".jar"));if (jarFiles == null) {return;}for (File jarFile : jarFiles) {HotClassLoader.loadJar(jarFile.getAbsolutePath());}}
}

(三)Spring Bean动态注册

为了使加载的Jar包中的类能够被Spring容器管理,我们需要动态地注册这些类为Spring Bean。以下是BeanRegistrar类的实现:

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;import java.util.Set;public class BeanRegistrar {private final ApplicationContext applicationContext;private final BeanDefinitionRegistry registry;public BeanRegistrar(ApplicationContext applicationContext) {this.applicationContext = applicationContext;this.registry = (BeanDefinitionRegistry) applicationContext.getBeanFactory();}public void registerBeans(String basePackage) {ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));Set<BeanDefinition> candidates = scanner.findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {GenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition.setBeanClass(candidate.getBeanClassName());registry.registerBeanDefinition(candidate.getBeanClassName(), beanDefinition);System.out.println("Registered bean: " + candidate.getBeanClassName());}}
}

(四)文件上传接口

为了方便用户上传新的Jar包,我们需要提供一个文件上传接口。以下是JarUploadController的实现:

import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;@RestController
@RequestMapping("/api/plugins")
public class JarUploadController {private static final String PLUGIN_DIR = "plugins/";@PostMapping("/upload")public String uploadJar(@RequestParam("file") MultipartFile file) {File pluginDir = new File(PLUGIN_DIR);if (!pluginDir.exists()) {pluginDir.mkdirs();}File destFile = new File(pluginDir, file.getOriginalFilename());try {file.transferTo(destFile);try {HotClassLoader.loadJar(destFile.getAbsolutePath());} catch (IOException e) {e.printStackTrace();return "Failed to load jar file: " + file.getOriginalFilename();}return "Jar file uploaded and loaded successfully: " + file.getOriginalFilename();} catch (IOException e) {e.printStackTrace();return "Failed to upload jar file: " + file.getOriginalFilename();}}
}

(五)主应用启动类

以下是主应用启动类的实现,它会在应用启动时加载插件目录下的Jar包,并注册为Spring Bean:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class Application {public static void main(String[] args) throws Exception {ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);BeanRegistrar beanRegistrar = new BeanRegistrar(context);beanRegistrar.registerBeans("com.example.plugins");// Load jars on startupJarLoader.loadJars();}
}

四、完整代码示例

以下是完整的代码实现,包括自定义类加载器、Jar包加载器、Bean注册器和文件上传接口:

// HotClassLoader.java
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;public class HotClassLoader extends URLClassLoader {private static final Map<String, Long> jarLastModifiedMap = new HashMap<>();public HotClassLoader(URL[] urls, ClassLoader parent) {super(urls, parent);}public static synchronized void loadJar(String jarPath) throws IOException {File jarFile = new File(jarPath);if (!jarFile.exists()) {throw new IOException("Jar file does not exist: " + jarPath);}long lastModified = jarFile.lastModified();if (jarLastModifiedMap.containsKey(jarPath) && jarLastModifiedMap.get(jarPath) == lastModified) {System.out.println("Jar file has not changed: " + jarPath);return;}URL url = jarFile.toURI().toURL();URLClassLoader loader = new HotClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());jarLastModifiedMap.put(jarPath, lastModified);System.out.println("Loaded jar: " + jarPath);}public static synchronized void unloadJar(String jarPath) {if (!jarLastModifiedMap.containsKey(jarPath)) {System.out.println("Jar file is not loaded: " + jarPath);return;}jarLastModifiedMap.remove(jarPath);System.out.println("Unloaded jar: " + jarPath);}
}// JarLoader.java
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;public class JarLoader {private static final String PLUGIN_DIR = "plugins/";public static void loadJars() throws IOException {File pluginDir = new File(PLUGIN_DIR);if (!pluginDir.exists()) {pluginDir.mkdirs();}File[] jarFiles = pluginDir.listFiles((dir, name) -> name.endsWith(".jar"));if (jarFiles == null) {return;}for (File jarFile : jarFiles) {HotClassLoader.loadJar(jarFile.getAbsolutePath());}}
}// BeanRegistrar.java
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;import java.util.Set;public class BeanRegistrar {private final ApplicationContext applicationContext;private final BeanDefinitionRegistry registry;public BeanRegistrar(ApplicationContext applicationContext) {this.applicationContext = applicationContext;this.registry = (BeanDefinitionRegistry) applicationContext.getBeanFactory();}public void registerBeans(String basePackage) {ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);scanner.addIncludeFilter(new AnnotationTypeFilter(Component.class));Set<BeanDefinition> candidates = scanner.findCandidateComponents(basePackage);for (BeanDefinition candidate : candidates) {GenericBeanDefinition beanDefinition = new GenericBeanDefinition();beanDefinition.setBeanClass(candidate.getBeanClassName());registry.registerBeanDefinition(candidate.getBeanClassName(), beanDefinition);System.out.println("Registered bean: " + candidate.getBeanClassName());}}
}// JarUploadController.java
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;@RestController
@RequestMapping("/api/plugins")
public class JarUploadController {private static final String PLUGIN_DIR = "plugins/";@PostMapping("/upload")public String uploadJar(@RequestParam("file") MultipartFile file) {File pluginDir = new File(PLUGIN_DIR);if (!pluginDir.exists()) {pluginDir.mkdirs();}File destFile = new File(pluginDir, file.getOriginalFilename());try {file.transferTo(destFile);try {HotClassLoader.loadJar(destFile.getAbsolutePath());} catch (IOException e) {e.printStackTrace();return "Failed to load jar file: " + file.getOriginalFilename();}return "Jar file uploaded and loaded successfully: " + file.getOriginalFilename();} catch (IOException e) {e.printStackTrace();return "Failed to upload jar file: " + file.getOriginalFilename();}}
}// Application.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication
public class Application {public static void main(String[] args) throws Exception {ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);BeanRegistrar beanRegistrar = new BeanRegistrar(context);beanRegistrar.registerBeans("com.example.plugins");// Load jars on startupJarLoader.loadJars();}
}

五、注意事项

  1. 安全性:允许用户上传Jar包可能会引入安全风险,例如恶意代码注入。建议在生产环境中对上传的Jar包进行严格的验证和扫描。
  2. 依赖管理:动态加载的Jar包可能会依赖其他库,需要确保这些依赖在运行时可用。
  3. 线程安全:在多线程环境下,类加载器的使用需要确保线程安全。
  4. 资源清理:当卸载Jar包时,需要确保释放所有相关资源,避免内存泄漏。

六、测试步骤

  1. 创建一个plugins目录,并将需要动态加载的Jar包放入其中。
  2. 启动Spring Boot应用。
  3. 使用Postman或其他工具上传新的Jar包到/api/plugins/upload接口。
  4. 检查是否成功加载并注册了新的Bean。

七、总结

本文详细介绍了在Spring Boot应用中实现Jar包热更新的方法,包括自定义类加载器的实现、Spring Bean的动态注册、文件上传接口的开发以及热更新流程的设计。通过这些技术,我们可以实现无需重启应用即可动态更新Jar包的功能,提高开发效率并减少对用户的影响。希望本文能够帮助大家快速掌握这一技术,并应用于实际项目中。

相关文章:

Spring Boot应用中实现Jar包热更新的实践指南

Spring Boot应用中实现Jar包热更新的实践指南 一、引言 在现代软件开发中&#xff0c;快速迭代和持续交付是至关重要的。对于基于Spring Boot的应用程序&#xff0c;一旦部署到生产环境&#xff0c;传统的更新方式通常是重新打包并重启应用&#xff0c;这不仅耗时&#xff0c…...

JVM深入原理(七)(一):运行时数据区

目录 7. JVM运行时数据区 7.1. 运行时数据区-总览 7.2. 运行时数据区-查看内存对象 7.3. 运行时数据区-程序计数器 7.3.1. 程序计数器-作用 7.3.2. 字节码指令执行流程 7.4. 运行时数据区-Java虚拟机栈 7.4.1. 栈-概述 7.4.2. 栈帧-组成 7.4.2.1. 栈帧-帧数据 7.4.2…...

约瑟夫环的四种(数组,链表,递归,迭代)解决方案,与空间、时间复杂度分析

以下方法均没有考虑结果集的空间与时间复杂度 1.数组解法 实现代码&#xff08;未优化&#xff09; class Main {public static void main(String[] args){Scanner read new Scanner(System.in);int n read.nextInt();int m read.nextInt();int[] people new int[n]; //…...

skynet.start 的作用详细解析

目录 skynet.start 的作用详细解析1. 功能概述2. 基本用法3. 关键作用(1) 注册消息处理函数(2) 启动事件循环(3) 服务生命周期管理 4. 与其他函数的协作5. 未调用 skynet.start 的后果6. 高级场景&#xff1a;何时不需要 skynet.start7. 总结 skynet.start 的作用详细解析 在 …...

Apache Doris 2025 Roadmap:构建 GenAI 时代实时高效统一的数据底座

在全球 290 位开发者的协作下&#xff0c;Apache Doris 在 2024 年完成了 7000 次代码提交&#xff0c;并发布了 22 个版本&#xff0c;实现在实时分析、湖仓一体和半结构化数据分析等核心场景的技术突破及创新。 2025 年&#xff0c;Apache Doris 社区将秉承“以场景驱动创新…...

springboot+easyexcel实现下载excels模板下拉选择

定义下拉注解 Target(ElementType.FIELD) Retention(RetentionPolicy.RUNTIME) public interface ExcelDropDown {/*** 固定下拉选项*/String[] source() default {};/*** 动态数据源key&#xff08;从上下文中获取&#xff09;*/String sourceMethod() default "";…...

vue3+ts+element-plus 开发一个页面模块的详细过程

目录、文件名均使用kebab-case&#xff08;短横线分隔式&#xff09;命名规范 子组件目录&#xff1a;./progress-ctrl/comps 1、新建页面文件 progress-ctrl.vue <script setup lang"ts" name"progress-ctrl"></script><template>&l…...

软考《信息系统运行管理员》- 7.1 物联网运维

物联网的概念及特征 物联网是在计算机互联网的基础上&#xff0c;通过射频识别 (RFID) 、 无线传感器、红外感应器、 全球定位系统、激光扫描器等信息传感设备&#xff0c;按约定的协议&#xff0c;把物与物之间通过网络连接起来&#xff0c; 进行信息交换和通信&#xff0c;以…...

【GPT入门】第33 课 一文吃透 LangChain:chain 结合 with_fallbacks ([]) 的实战指南

[TOC](【GPT入门】第33课 一文吃透 LangChain&#xff1a;chain 结合 with_fallbacks ([]) 的实战指南) 1. fallback概述 模型回退&#xff0c;可以设置在llm上&#xff0c;也可以设置在chain上&#xff0c;都带有with_fallbacks([])函数 2. llm的回退 2.1 代码 核心代码&…...

裴蜀定理:整数解的奥秘

裴蜀定理&#xff1a;整数解的奥秘 在数学的世界里&#xff0c;裴蜀定理&#xff08;Bzout’s Theorem&#xff09;是数论中一个非常重要的定理&#xff0c;它揭示了二次方程和整数解之间的关系。它不仅仅是纯粹的理论知识&#xff0c;还在计算机科学、密码学、算法优化等多个…...

Table as Thought论文精读

标题&#xff1a;Table as Thought: Exploring Structured Thoughts in LLM Reasoning 作者&#xff1a;Zhenjie Sun, Naihao Deng, Haofei Yu, Jiaxuan You 单位&#xff1a;University of Illinois Urbana-Champaign, University of Michigan 摘要&#xff1a; llm的推理…...

PyQt6实例_A股日数据维护工具_使用

目录 前置&#xff1a; 下载预备更新的数据 使用工具更新 用工具下载未复权、前复权、权息数据 在PostgreSQL添加两个数据表 工具&视频 前置&#xff1a; 1 本系列将以 “PyQt6实例_A股日数据维护工具” 开头放置在“PyQt6实例”专栏 2 日数据可在“数据库”专栏&…...

MySQL客户端工具-图形化工具-DataGrip 安装与使用

一. 常见的图形化工具 二. DataGrip 安装 官网&#xff1a;DataGrip&#xff1a;由 JetBrains 开发的数据库和 SQL 跨平台 IDE 二. DataGrip 使用...

企业管理系统的功能架构设计与实现

一、企业管理系统的核心功能模块 企业管理系统作为现代企业的中枢神经系统&#xff0c;涵盖了多个核心功能模块&#xff0c;以确保企业运营的顺畅与高效。这些功能模块通常包括&#xff1a; 人力资源管理模块&#xff1a;负责员工信息的录入、维护、查询及统计分析&#xff0c…...

1.Qt信号与槽

本篇主要介绍信号和槽&#xff0c;如何关联信号和槽以及用QPixmap在窗口中自适应显示图片 本文部分ppt、视频截图原链接&#xff1a;[萌马工作室的个人空间-萌马工作室个人主页-哔哩哔哩视频] 1. 信号 一般不需要主动发送信号&#xff0c;只有自定义的一些控件才需要做信号的…...

再生认证体系有哪些?不同标准对应的要求及可以做的审核机构

再生认证体系 标准 GRS再生回收认证要求 再生原材料的上游企业&#xff1a;需要具备GRS认证证书&#xff0c;以确保原材料的可追溯性和再生成分。 认证条件&#xff1a; 最终商品的再生成分比例必须至少为20%。 只有由至少50%的回收材料制成的产品才能贴上GRS标签。 认证机构…...

[CISSP] [6] 密码学和对称密钥算法

密码学的目标 1. 机密性&#xff08;Confidentiality&#xff09; 目标&#xff1a;保护信息不被未授权访问。 通过 加密&#xff08;Encryption&#xff09;技术确保数据只能被授权方解密和读取。主要方法&#xff1a; 对称加密&#xff08;AES、3DES&#xff09;&#xff…...

thinkphp每条一级栏目中可自定义添加多条二级栏目,每条二级栏目包含多个字段信息

小程序客户端需要展示团购详情这种结构的内容,后台会新增多条套餐,每条套餐可以新增多条菜品信息,每条菜品信息包含菜品名称,价格,份数等字段信息,类似于购物网的商品多规格属性,数据表中以json类型存储,手写了一个后台添加和编辑的demo 添加页面 编辑页面(json数据…...

混杂模式(Promiscuous Mode)与 Trunk 端口的区别详解

一、混杂模式&#xff08;Promiscuous Mode&#xff09; 1. 定义与工作原理 定义&#xff1a;混杂模式是网络接口的一种工作模式&#xff0c;允许接口接收通过其物理链路的所有数据包&#xff0c;而不仅是目标地址为本机的数据包。工作层级&#xff1a;OSI 数据链路层&#x…...

Spring Boot项目信创国产化适配指南

将 Spring Boot 项目适配信创国产化环境&#xff0c;需要从底层基础设施到上层应用组件进行全面替换和调整。以下是主要替换点和适配步骤的总结&#xff1a; 一、基础软件替换 1. JDK 替换 国外JDK&#xff1a;Oracle JDK、OpenJDK国产JDK&#xff1a; 阿里龙井&#xff08;D…...

MySQL:数据类型

数值类型 数值类型用于存储整数、小数、浮点数等&#xff0c;主要分为整数类型和浮点类型。 整数类型 数据类型存储大小取值范围&#xff08;有符号&#xff09;取值范围&#xff08;无符号&#xff09;说明TINYINT1字节-128 ~ 1270 ~ 255小整数&#xff0c;如布尔值&#x…...

maven引入项目内本地包方法

最近在写java实现excel转pdf功能&#xff1b; 网上有个包很好用&#xff0c;免费&#xff1a;spire.xls.free-5.3.0.jar。 但是maven打包项目时报错&#xff0c;找不到这个包。 jar包位置如下&#xff1a; 在项目/src/jar/spire.xls.free-5.3.0.jar。 解决方法&#xff1a…...

ARP协议

ARP协议 ARP协议的作用 当网络设备有数据要发送给另一台网络设备时&#xff0c;必须要知道对方的网络层地址&#xff08;即IP地址&#xff09;。IP地址由网络层来提供&#xff0c;但是仅有IP地址是不够的&#xff0c;IP数据报文必须封装成帧才能通过数据链路进行发送。数据帧…...

科技赋能安居梦:中建海龙以模块化革新重塑城市更新范式

在北京市西城区桦皮厂胡同&#xff0c;一栋始建于上世纪70年代的住宅楼正经历着一场脱胎换骨的蜕变。这座曾被鉴定为D级危房的建筑&#xff0c;在中建海龙科技有限公司&#xff08;以下简称“中建海龙”&#xff09;的匠心打造下&#xff0c;仅用三个月便完成"原拆原建&qu…...

2025 AI智能数字农业研讨会在苏州启幕,科技助农与数据兴业成焦点

4月2日&#xff0c;以"科技助农数据兴业”为主题的2025AI智能数字农业研讨会在苏州国际博览中心盛大启幕。本次盛会吸引了来自全国各地相关部门领导、知名专家学者、行业协会组织&#xff0c;以及县级市农业企业代表、县级市农产品销售商等万名嘉宾齐聚姑苏城&#xff0c;…...

2000-2021年 全国各地区城镇登记失业率数据

全国各地区城镇登记失业率数据2000-2021年.ziphttps://download.csdn.net/download/2401_84585615/90259723 https://download.csdn.net/download/2401_84585615/90259723 城镇登记失业率是衡量地区就业状况的重要指标&#xff0c;反映了在一定时期内&#xff0c;符合就业条件的…...

Cursor的主要好处

以下是Cursor的主要好处&#xff1a; 代码生成与优化 • 快速生成代码&#xff1a;根据简短描述或部分代码片段&#xff0c;Cursor能快速生成完整代码模块&#xff0c;还能智能预测下一步操作&#xff0c;将光标放在合适位置&#xff0c;让开发者一路Tab键顺滑编写代码。 • …...

超便捷语音转文字工具CapsWriter-Offline本地部署与远程使用全流程

文章目录 前言1. 软件与模型下载2. 本地使用测试3. 异地远程使用3.1 内网穿透工具下载安装3.2 配置公网地址3.3 修改config文件3.4 异地远程访问服务端 4. 配置固定公网地址4.1 修改config文件 5. 固定tcp公网地址远程访问服务端 前言 今天给大家安利一个绝对能让你工作效率飙…...

什么是数据仓库

什么是数据仓库 Data warehouse 是面向主题的 主要根据各种数据来源&#xff0c;来进行历史分析 形成一个趋势分析 为数据挖掘、预测建模、机器学习提供基础数据 与传统数据库比如gaussdb的区别。数据仓库注重历史数据分析&#xff0c;guassdb注重实时事务处理 数据仓库时企业的…...

【动态规划】二分优化最长上升子序列

最长上升子序列 II 题解 题目传送门&#xff1a;AcWing 896. 最长上升子序列 II 一、题目描述 给定一个长度为 N 的数列&#xff0c;求数值严格单调递增的子序列的长度最长是多少。 输入格式&#xff1a; 第一行包含整数 N第二行包含 N 个整数&#xff0c;表示完整序列 输…...

MySQL的安装与初始化流程

MySQL概述 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB公司开发&#xff0c;MySQL AB公司被Sun公司收购&#xff0c;Sun公司又被Oracle公司收购&#xff0c;目前属于Oracle公司。 MySQL是目前最流行的关系型数据库管理系统&#xff0c;在WEB应用方面MySQL是最…...

flink standalone集群模式部署

一. 环境准备 1、下载并安装jdk11 2、下载flink 并解压 3、确保服务器之间的免密登录 二、集群搭建 搭建集群至少有三台机器&#xff0c;每台机器的分配角色如下 master: jobManager salve01&#xff1a;taskManager salve02&#xff1a;taskManager 1、在JobManager(…...

Linux线程概念与控制:【线程概念(页表)】【Linux线程控制】【线程ID及进程地址空间布局】【线程封装】

目录 一. 线程概念 1.1什么是线程 1.2分页式存储管理 1.2.1虚拟地址和页表的由来 1.2.2物理内存管理 1.2.3页表 1.2.4页目录结构 1.2.5二级页表地址转换 1.3线程的优点 二.进程VS线程 三.Linux线程控制 3.1POSIX线程库 3.2创建线程 ​编辑 pthread库是个什么东西 …...

7-6 混合类型数据格式化输入

本题要求编写程序&#xff0c;顺序读入浮点数1、整数、字符、浮点数2&#xff0c;再按照字符、整数、浮点数1、浮点数2的顺序输出。 输入格式&#xff1a; 输入在一行中顺序给出浮点数1、整数、字符、浮点数2&#xff0c;其间以1个空格分隔。 输出格式&#xff1a; 在一行中…...

最新全开源码支付系统,赠送3套模板

最新全开源码支付系统&#xff0c;赠送3套模板 码支付是专为个人站长打造的聚合免签系统&#xff0c;拥有卓越的性能和丰富的功能。它采用全新轻量化的界面UI 让您能更方便快捷地解决知识付费和运营赞助的难题&#xff0c;同时提供实时监控和管理功能&#xff0c;让您随时随地…...

Eclipse Leshan 常见问题解答 (FAQ) 笔记

本笔记基于 Eclipse Leshan Wiki - F.A.Q. 页面内容&#xff0c;旨在解答关于 Eclipse Leshan&#xff08;一个开源的 LwM2M 服务器和客户端 Java 实现&#xff09;的常见问题&#xff0c;帮助您更好地理解和使用该工具。 一、Leshan 是什么&#xff0c;我该如何使用它&#x…...

【6】数据结构的栈篇章

目录标题 栈的定义顺序栈的实现顺序栈的初始化入栈出栈获取栈顶元素顺序栈总代码与调试 双端栈的实现双端栈的初始化入栈出栈双端栈总代码与调试 链栈的实现链栈的初始化入栈出栈获取栈顶元素链栈总代码与调试 栈的定义 定义&#xff1a;栈&#xff08;Stack&#xff09;是一种…...

开源虚拟化管理平台Proxmox VE部署超融合

Proxmox VE 是一个功能强大、开源的虚拟化平台&#xff0c;结合了 KVM 和 LXC&#xff0c;同时支持高可用集群、存储管理&#xff08;ZFS、Ceph&#xff09;和备份恢复。相比 VMware ESXi 和 Hyper-V&#xff0c;PVE 具有开源、低成本、高灵活性的特点&#xff0c;适用于中小企…...

C语言基础要素(019):输出ASCII码表

计算机以二进制处理信息&#xff0c;但二进制对人类并不友好。比如说我们规定用二进制值 01000001 表示字母’A’&#xff0c;显然通过键盘输入或屏幕阅读此数据而理解它为字母A&#xff0c;是比较困难的。为了有效的使用信息&#xff0c;先驱者们创建了一种称为ASCII码的交换代…...

函数柯里化(Currying)介绍(一种将接受多个参数的函数转换为一系列接受单一参数的函数的技术)

文章目录 柯里化的特点示例普通函数柯里化实现使用Lodash进行柯里化 应用场景总结 函数柯里化&#xff08;Currying&#xff09;是一种将接受多个参数的函数转换为一系列接受单一参数的函数的技术。换句话说&#xff0c;柯里化将一个多参数函数转化为一系列嵌套的单参数函数。 …...

基于大模型的主动脉瓣病变预测及治疗方案研究报告

目录 一、引言 1.1 研究背景 1.2 研究目的 1.3 研究意义 二、大模型预测主动脉瓣病变原理 2.1 大模型介绍 2.2 数据收集与处理 2.3 模型训练与优化 三、术前预测与评估 3.1 主动脉瓣病变类型及程度预测 3.2 患者整体状况评估 3.3 手术风险预测 四、术中应用与监测…...

VSCode开发者工具快捷键

自动生成浏览器文件.html的快捷方式 在文本里输入&#xff1a; &#xff01; enter VSCode常用快捷键列表 代码格式化&#xff1a;Shift Alt F向上或向下移动一行&#xff1a;Alt Up 或者 Alt Down快速复制一行代码&#xff1a;Shift Alt Up 或者 Shift Alt Down快速保…...

AI助力PPT制作,让演示变得轻松高效

AI助力PPT制作&#xff0c;让演示变得轻松高效&#xff01;随着科技的进步&#xff0c;AI技术早已渗透到各行各业&#xff0c;特别是在办公领域&#xff0c;AI制作PPT已不再是未来的梦想&#xff0c;而是现实的工具。以前你可能需要花费数小时来制作一个完美的PPT&#xff0c;如…...

行业专家视角下的技术选型与任务适配深度解析

行业专家视角下的技术选型与任务适配深度解析 一、任务属性与技术栈的映射逻辑 &#xff08;1&#xff09;学术类项目需优先考虑技术严谨性、可复现性和理论深度&#xff1a; 机器学习模型开发&#xff1a;PyTorchJupyterMLflow形成完整实验闭环&#xff0c;TensorFlow Exte…...

从零构建大语言模型全栈开发指南:第五部分:行业应用与前沿探索-5.2.1模型偏见与安全对齐(Red Teaming实践)

👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 大语言模型全栈开发指南:伦理与未来趋势 - 第五部分:行业应用与前沿探索5.2.1 模型偏见与安全对齐(Red Teaming实践)一、模型偏见的来源与影响1. 偏见的定义与分类2. 偏见的实际影响案例二、安全对齐…...

JUC系列JMM学习之随笔

JUC: JUC 是 Java 并发编程的核心工具包,全称为 Java Util Concurrent,是 java.util.concurrent 包及其子包的简称。它提供了一套强大且高效的并发编程工具,用于简化多线程开发并提高性能。 CPU核心数和线程数的关系:1核处理1线程(同一时间单次) CPU内核结构: 工作内…...

OpenRouter开源的AI大模型路由工具,统一API调用

简介 ‌OpenRouter是一个开源的路由工具‌&#xff0c;它可以绕过限制调用GPT、Claude等国外模型。以下是对它的详细介绍&#xff1a; 一、主要功能 OpenRouter专注于将用户请求智能路由到不同的AI模型&#xff0c;并提供统一的访问接口。它就像一个“路由器”&#xff0c;能…...

3.9/Q2,Charls最新文章解读

文章题目&#xff1a;Association between remnant cholesterol and depression in middle-aged and older Chinese adults: a population-based cohort study DOI&#xff1a;10.3389/fendo.2025.1456370 中文标题&#xff1a;中国中老年人残留胆固醇与抑郁症的关系&#xff1…...

水下图像增强与目标检测:标签缺失的“锅”?

水下图像增强与目标检测&#xff1a;标签缺失的“锅”&#xff1f; 在水下计算机视觉领域&#xff0c;图像增强和目标检测一直是研究热点。然而&#xff0c;一个有趣的现象引起了研究者的关注&#xff1a;在某些情况下&#xff0c;增强后的水下图像用于目标检测时&#xff0c;…...

从扩展黎曼泽塔函数构造物质和时空的结构-13

得到这些数据到底有什么用呢&#xff1f;无非都是振动&#xff0c;只有频率不同。电性振动和磁性振动的正交环绕关系&#xff0c;本质上只是某个虚数单位的平方倍数&#xff0c; 既然如此&#xff0c;我们就可以考虑&#xff0c;把电和磁当成同一种东西。比如通过改变真空介电常…...