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

反射与注解实现动态功能扩展案例-插件系统

学海无涯,志当存远。燃心砺志,奋进不辍。

愿诸君得此鸡汤,如沐春风,事业有成。

若觉此言甚善,烦请赐赞一枚,共励学途,同铸辉煌!

开发一个需要高度扩展性的应用,比如Web框架、插件系统或者工作流引擎。
通过注解来标记某些类或方法,然后利用反射在运行时动态加载这些组件,从而实现功能的扩展。
例如,Spring框架中的控制器和路由映射就是类似的做法。一个完整的代码示例,展示如何定义注解,如何使用反射扫描类路径,发现被注解标记的类或方法,
并动态调用或注册这些功能。案例方向包括:动态路由映射、插件系统、事件监听器、权限校验等。
比如,定义一个@Handler注解,标记处理特定类型请求的类,然后通过反射扫描所有带有该注解的类,
根据注解中的参数动态注册处理器。反射的性能问题,如何处理类路径扫描,如何确保线程安全,或者如何处理依赖注入。
在案例中需要提到这些注意事项.然后,结构方面,应该分步骤讲解:定义注解、实现注解处理器(反射部分)、示例应用。
需要一个简单的测试类来展示效果。代码需要详细注释,说明每一步的作用,以及反射的关键点,
比如获取注解信息、实例化对象、调用方法等。要注意案例的实用性,比如模拟一个简单的插件系统,主程序启动时扫描所有插件,加载并执行。
或者一个简单的命令行工具,根据用户输入动态调用不同的命令处理器,这些处理器通过注解注册。最后,总结反射与注解结合的优势,比如降低耦合、提高扩展性,以及可能的缺点,
如性能开销和安全性问题,并给出适用场景的建议。

以下是结合 反射与注解 实现动态功能扩展的详细案例,以模拟一个 插件系统 为例,展示如何通过注解标记插件类,并在运行时动态加载并执行插件功能。


案例目标

  1. 定义 @Plugin 注解,标记插件类。

  2. 通过反射扫描类路径,动态加载所有被 @Plugin 标记的类。

  3. 根据注解参数执行插件逻辑。


一、定义注解 @Plugin

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME) // 注解保留到运行时
@Target(ElementType.TYPE)           // 只能标记类
public @interface Plugin {String name();        // 插件名称String version();     // 插件版本String description() default "No description"; // 插件描述(可选)
}

二、实现插件类

定义两个插件类,用 @Plugin 注解标记:

插件1:日志记录插件

@Plugin(name = "LoggerPlugin",version = "1.0",description = "记录系统日志"
)
public class LoggerPlugin {public void execute() {System.out.println("[LoggerPlugin] 正在记录日志...");}
}

插件2:数据备份插件

@Plugin(name = "BackupPlugin",version = "2.0",description = "执行数据备份"
)
public class BackupPlugin {public void runBackup() {System.out.println("[BackupPlugin] 数据备份完成!");}
}

三、反射扫描与动态加载

编写核心逻辑:通过反射扫描类路径,找到所有被 @Plugin 标记的类,并执行其方法。

import java.io.File;
import java.net.URL;
import java.util.*;public class PluginManager {// 存储所有插件实例private final Map<String, Object> plugins = new HashMap<>();/*** 扫描指定包路径下的所有类,加载被 @Plugin 标记的类*/public void loadPlugins(String packageName) throws Exception {// 获取类路径下的包路径String path = packageName.replace('.', '/');ClassLoader classLoader = Thread.currentThread().getContextClassLoader();Enumeration<URL> resources = classLoader.getResources(path);// 遍历包路径下的所有类文件while (resources.hasMoreElements()) {URL resource = resources.nextElement();File file = new File(resource.getFile());scanClasses(file, packageName);}}/*** 扫描目录中的类文件*/private void scanClasses(File directory, String packageName) throws Exception {File[] files = directory.listFiles();if (files == null) return;for (File file : files) {if (file.isDirectory()) {// 递归扫描子目录scanClasses(file, packageName + "." + file.getName());} else if (file.getName().endsWith(".class")) {// 加载类String className = packageName + '.' + file.getName().replace(".class", "");Class<?> clazz = Class.forName(className);// 检查是否被 @Plugin 标记if (clazz.isAnnotationPresent(Plugin.class)) {Plugin annotation = clazz.getAnnotation(Plugin.class);Object instance = clazz.getDeclaredConstructor().newInstance();plugins.put(annotation.name(), instance);System.out.println("加载插件: " + annotation.name() + " v" + annotation.version());}}}}/*** 执行插件功能*/public void executePlugin(String pluginName) throws Exception {Object plugin = plugins.get(pluginName);if (plugin == null) {throw new IllegalArgumentException("插件不存在: " + pluginName);}// 动态查找并执行方法(假设插件有 execute() 或 runBackup() 方法)try {plugin.getClass().getMethod("execute").invoke(plugin);} catch (NoSuchMethodException e) {plugin.getClass().getMethod("runBackup").invoke(plugin);}}public static void main(String[] args) throws Exception {PluginManager manager = new PluginManager();manager.loadPlugins("com.example.plugins"); // 假设插件在 com.example.plugins 包下manager.executePlugin("LoggerPlugin");manager.executePlugin("BackupPlugin");}
}

四、运行结果

加载插件: LoggerPlugin v1.0
加载插件: BackupPlugin v2.0
[LoggerPlugin] 正在记录日志...
[BackupPlugin] 数据备份完成!

五、关键实现细节

1. 类路径扫描

  • 通过 ClassLoader.getResources() 获取包路径下的资源。

  • 递归扫描目录,加载所有 .class 文件。

2. 反射与注解处理

  • Class.forName(className):动态加载类。

  • clazz.isAnnotationPresent(Plugin.class):检查类是否被 @Plugin 标记。

  • clazz.getAnnotation(Plugin.class):获取注解信息。

3. 动态方法调用

  • getMethod("execute"):反射查找方法。

  • invoke(plugin):执行方法,无需提前知道具体实现。


六、扩展方向

1. 依赖注入

通过注解标记需要注入的字段,动态注入依赖(类似 Spring 的 @Autowired):

public class DatabasePlugin {@Injectprivate DataSource dataSource; // 动态注入
}

2. 插件配置

通过注解定义配置参数,动态读取配置文件:

@Plugin(name = "EmailPlugin", configFile = "email-config.properties")
public class EmailPlugin { ... }

3. 优先级控制

通过注解标记插件执行顺序:

@Plugin(name = "HighPriorityPlugin", priority = 1)
public class HighPriorityPlugin { ... }

七、反射与注解的优势

  1. 低耦合:新增插件只需添加类并用 @Plugin 标记,无需修改主程序。

  2. 动态扩展:运行时加载功能,适合插件化架构。

  3. 灵活性:通过注解参数控制行为,无需硬编码。


通过此案例,可以清晰理解如何结合反射与注解实现动态功能扩展。类似机制广泛应用于 Spring、Quarkus 等框架的核心设计。

八、公共案例

如何使用Java反射和注解实现动态功能扩展。

1. 定义功能注解

首先创建一个自定义注解,用于标记可扩展的功能:

package com.example.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DynamicFunction {String name(); // 功能名称int priority() default 0; // 执行优先级boolean enabled() default true; // 是否启用
}

2. 创建功能接口

定义功能接口作为扩展点:

package com.example.service;public interface Function {void execute(Object... params);
}

3. 实现具体功能

创建几个具体功能实现类,使用注解标记:

package com.example.service.impl;import com.example.annotation.DynamicFunction;
import com.example.service.Function;@DynamicFunction(name = "日志记录", priority = 1)
public class LogFunction implements Function {@Overridepublic void execute(Object... params) {System.out.println("记录日志: " + params[0]);}
}
package com.example.service.impl;import com.example.annotation.DynamicFunction;
import com.example.service.Function;@DynamicFunction(name = "消息通知", priority = 2)
public class NotifyFunction implements Function {@Overridepublic void execute(Object... params) {System.out.println("发送通知: " + params[0]);}
}

4. 创建功能管理器

实现动态加载和执行功能的处理器:

package com.example.core;import com.example.annotation.DynamicFunction;
import com.example.service.Function;
import org.reflections.Reflections;import java.util.*;
import java.util.stream.Collectors;public class FunctionManager {private final Map<String, Function> functions = new HashMap<>();public FunctionManager(String basePackage) {// 扫描指定包下的所有功能实现Reflections reflections = new Reflections(basePackage);Set<Class<?>> annotatedClasses = reflections.getTypesAnnotatedWith(DynamicFunction.class);// 实例化并注册功能annotatedClasses.forEach(clazz -> {try {DynamicFunction annotation = clazz.getAnnotation(DynamicFunction.class);if (annotation.enabled()) {Function function = (Function) clazz.newInstance();functions.put(annotation.name(), function);}} catch (Exception e) {e.printStackTrace();}});}// 按优先级执行所有功能public void executeAll(Object... params) {functions.values().stream().sorted(Comparator.comparingInt(f -> f.getClass().getAnnotation(DynamicFunction.class).priority())).forEach(f -> f.execute(params));}// 执行指定功能public void executeByName(String name, Object... params) {Function function = functions.get(name);if (function != null) {function.execute(params);}}
}

5. 测试代码

创建测试类验证功能:

package com.example;import com.example.core.FunctionManager;
import org.junit.jupiter.api.Test;public class FunctionTest {@Testpublic void testDynamicFunctions() {// 初始化功能管理器,扫描com.example包FunctionManager manager = new FunctionManager("com.example");// 执行所有功能(按优先级顺序)System.out.println("=== 执行所有功能 ===");manager.executeAll("测试参数");// 执行单个功能System.out.println("\n=== 执行单个功能 ===");manager.executeByName("日志记录", "特定日志");}
}

6. 运行结果

执行测试后预期输出:

=== 执行所有功能 ===
记录日志: 测试参数
发送通知: 测试参数=== 执行单个功能 ===
记录日志: 特定日志

关键点说明

  1. 动态发现:通过反射扫描指定包下的所有类,查找带有@DynamicFunction注解的类
  2. 优先级控制:通过注解的priority属性控制功能执行顺序
  3. 灵活扩展:新增功能只需实现Function接口并添加注解,无需修改核心代码
  4. 按需执行:可以执行所有功能或指定名称的功能

这种模式非常适合需要动态扩展功能的系统,如插件系统、任务调度系统等。

学海无涯,志当存远。燃心砺志,奋进不辍。

愿诸君得此鸡汤,如沐春风,事业有成。

若觉此言甚善,烦请赐赞一枚,共励学途,同铸辉煌!

 

相关文章:

反射与注解实现动态功能扩展案例-插件系统

学海无涯&#xff0c;志当存远。燃心砺志&#xff0c;奋进不辍。 愿诸君得此鸡汤&#xff0c;如沐春风&#xff0c;事业有成。 若觉此言甚善&#xff0c;烦请赐赞一枚&#xff0c;共励学途&#xff0c;同铸辉煌&#xff01; 开发一个需要高度扩展性的应用&#xff0c;比如Web框…...

auto(x) decay copy

该提案为auto又增加了两个新语法&#xff1a;auto(x) 和auto{x}。两个作用一样&#xff0c;只是写法不同&#xff0c;都 是为x 创建一份拷贝。 为什么需要这么个东西&#xff1f;看一个例子&#xff1a; void bar(const auto&);void foo(const auto& param) {auto co…...

基于STM32、HAL库的DS2411R安全验证及加密芯片驱动程序设计

一、简介: DS2411R是Maxim Integrated(现为Analog Devices)生产的一款1-Wire硅序列号芯片,具有以下特点: 64位唯一ROM序列号(包括8位家族码、48位序列号和8位CRC校验码) 工作电压范围:2.8V至5.25V 工作温度范围:-40C至+85C 采用TO-92或SOT-223封装 通过1-Wire协议通信…...

疫苗接种体系进入“全生命周期”时代:公共卫生治理再提速

疫苗接种体系进入“全生命周期”时代&#xff1a;公共卫生治理再提速 在防控重大传染病的国家公共卫生战略中&#xff0c;疫苗接种始终处于基础性、先导性地位。2025年4月25日是第39个全国儿童预防接种日&#xff0c;活动主题为“打疫苗、防疾病、保健康”。近年来&#xff0c…...

zynq 7010 PS 串口打印

前言 之前写过一篇文章《zynq 7010 PL 点灯例程》&#xff0c;介绍的是 zynq PL 部分的使用&#xff0c;今天这篇文章则是介绍 zynq PS 部分的使用。 在此之前&#xff0c;先总结点题外话 PL 编程&#xff0c;核心思想是生成 bitstream 文件&#xff0c;加载到 FPGA 运行PS …...

【补题】ACPC Kickoff 2025 F. Kinan The Bank Robber

题意&#xff1a;给出长度为n的序列&#xff0c;接下来给出了两个包裹&#xff0c;你可以选择把数字放进这两个包裹当中&#xff0c;要求你放的的方式&#xff0c;最终会让包裹内的数字双双互质&#xff0c;请你给出你的放法&#xff0c;如果没有输出-1 思路&#xff1a; 1.包…...

局域网传文件——基于flask实现

项目地址 git clone gitgitee.com:xhdx/co_-shared_-doc_in_-local_-net.git 所需python包 flask2.2.3 markdown3.4.1 bleach5.0.1 通过局域网的方式实现文件夹共享&#xff0c;共享的文件会放在uploads这个文件夹下&#xff1a; 运行界面&#xff1a; 包括预览、删除、下载等…...

苍穹外卖10

WebSocket WebSocket是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工通信----浏览器和服务器只需要完成一次握手&#xff0c;两者之间就可以创建持久性的连接&#xff0c;并进行双向数据传输。 HTTP协议和WebSocket协议对比&#xff1a; HTTP是短链接 WebSocke…...

第一天 车联网定义、发展历程与生态体系

前言 车联网&#xff08;Internet of Vehicles, IoV&#xff09;作为物联网&#xff08;IoT&#xff09;在汽车领域的延伸&#xff0c;正在彻底改变人们的出行方式。无论是自动驾驶、远程诊断&#xff0c;还是实时交通优化&#xff0c;车联网技术都扮演着核心角色。本文将从零…...

大模型(LLMs)强化学习—— PPO

一、大语言模型RLHF中的PPO主要分哪些步骤&#xff1f; 二、举例描述一下 大语言模型的RLHF&#xff1f; 三、大语言模型RLHF 采样篇 什么是 PPO 中 采样过程&#xff1f;介绍一下 PPO 中 采样策略&#xff1f;PPO 中 采样策略中&#xff0c;如何评估“收益”&#xff1f; …...

麻衣相法【麻衣相士】开篇

好久没有发布新的文章了,主要最近一方面没看书,时间基本都用来打游戏了;另一方面看的几本书实在是看不懂,就更不能写上来了。不过今天看到了《麻衣相法》这本书,就又点燃了本人的兴趣,以后失业了,可以摆个小摊子谋生! 话不多说,先把这本书开始的针对人的面部部位进行各…...

vLLM技术解析:大语言模型推理服务的性能革新引擎

vLLM大模型 vLLM&#xff08;Vectorized Large Language Model Serving System&#xff09;是由加州大学伯克利分校计算机系统研究团队开发的下一代大语言模型推理服务系统。作为专为现代化AI部署设计的开源框架&#xff0c;该系统通过突破性的内存架构创新和计算流程优化&…...

《无刷空心杯电机减速机选型及行业发展趋势》

无刷空心杯电机作为高精度驱动系统的核心部件,通常需搭配减速机以实现低转速、高扭矩输出。以下是当前主流的减速机类型、市场占比、参数对比及优劣势分析,结合行业数据与典型应用场景展开说明: 一、主流减速机类型及市场占比 1. 行星减速机 市场占比:约 45%-55%(工业自…...

Java锁的升级流程详解:无锁、偏向锁、轻量级锁、重量级锁

在Java中&#xff0c;为了在多线程并发场景下既保证线程安全&#xff0c;又尽可能提高性能&#xff0c;JVM针对synchronized实现了锁的优化升级机制。 锁可以从无锁逐步升级到偏向锁、轻量级锁&#xff0c;最后是重量级锁。 话不多说&#xff0c;发车&#xff01; 一、无锁&am…...

terraform local-exec与remote-exec详解

在 Terraform 中&#xff0c;local-exec 和 remote-exec 是两种常用的 provisioner&#xff08;资源调配器&#xff09;&#xff0c;用于在资源创建前后执行脚本或命令。它们的核心区别在于执行位置&#xff1a;local-exec 在运行 Terraform 的本地机器上执行命令&#xff0c;而…...

武装Burp Suite工具:APIKit插件_接口安全扫描.

武装Burp Suite工具&#xff1a;APIKit插件_接口安全扫描. API安全是指通过技术手段和管理措施保护应用程序接口&#xff08;API&#xff09;免受未授权访问、数据泄露或恶意攻击的防护体系&#xff0c;核心措施包括身份认证&#xff08;如OAuth2.0/JWT&#xff09;、权限控制…...

数据库系统概论|第三章:关系数据库标准语言SQL—课程笔记6

前言 经过前面几篇文章的介绍&#xff0c;已经完成了对于数据查询操作的介绍&#xff0c;接下来&#xff0c;本篇文章将介绍数据更新这一板块&#xff0c;包括插入数据、修改数据以及删除数据三种操作方法。 注&#xff1a;本文中所涉及的数据库前文中已经介绍&#xff08;指…...

如何在idea中写spark程序

1. 安装配置 Java 和 Scala Java&#xff1a;确保已安装合适版本的 Java Development Kit&#xff08;JDK&#xff09;&#xff0c;并配置好 JAVA_HOME 环境变量。Scala&#xff1a;由于 Spark 常用 Scala 语言编写&#xff0c;需安装 Scala 开发环境。可在 IDEA 中通过 Se…...

Linux428 chmod 0xxx 1xxx 2xxx 4xxx;umask;chown 属主属组 软件包rpm

sudo: 账户过期&#xff0c;或 PAM 配置缺少 sudo 使用的“account”节&#xff0c;联系您的系统管理员 这样子有没有用嘞 不行 为什么使用caozx26用户sudo修改了shop文件夹强制位&#xff0c;shop文件夹权限中不显示 成功了&#xff1f;真奇怪 查看文件夹权限用 -ld ch…...

基于强化学习的用于非刚性图像配准的引导式超声采集|文献速递-深度学习医疗AI最新文献

Title 题目 Guided ultrasound acquisition for nonrigid image registration usingreinforcement learning 基于强化学习的用于非刚性图像配准的引导式超声采集 01 文献速递介绍 超声成像通常用于引导手术和其他医疗程序&#xff0c;在这些过程中&#xff0c;临床医生会持…...

Shell脚本-嵌套循环应用案例

在Shell脚本编程中&#xff0c;嵌套循环是一种强大的工具&#xff0c;可以用于处理复杂的任务和数据结构。通过在一个循环内部再嵌套另一个循环&#xff0c;我们可以实现对多维数组、矩阵操作、文件处理等多种高级功能。本文将通过几个实际的应用案例来展示如何使用嵌套循环解决…...

QTableView复选框居中

目录 方法一&#xff1a;QSS方法2:自定义复选框委托类一、构造函数 CheckBoxDelegate()二、paint() 方法三、editorEvent() 方法四、关键设计要点五、扩展应用场景六、代码示例&#xff08;补充&#xff09; 方法一&#xff1a;QSS QTableView::indicator {position: relative…...

C语言教程(十八):C 语言共用体详解

一、共用体的定义 共用体的定义和结构体类似&#xff0c;使用 union 关键字&#xff0c;其基本语法如下&#xff1a; union 共用体名 { 数据类型 成员1; 数据类型 成员2; // 可以有更多成员 }; 以下是一个简单的共用体定义示例&#xff1a; union Data {int i;float f;char …...

企业办公系统开发如何重塑现代工作方式?

随着工作方式的革新&#xff0c;企业办公软件开发已成为提升组织效率的核心驱动力。从基础的文档处理到复杂的协同办公平台开发&#xff0c;现代办公系统正在彻底改变传统工作模式。本文将深入解析办公类软件的关键技术与发展趋势。 一、企业级办公系统开发的核心模块 专业的O…...

springboot 实现敏感信息脱敏

记录于2025年4月28号晚上--梧州少帅 1. 定义枚举类&#xff1a; public enum DesensitizeType {NAME, EMAIL } 2. 创建自定义注解&#xff1a; 用于标记需要脱敏的字段及其类型。 Retention(RetentionPolicy.RUNTIME) JacksonAnnotationsInside JsonSerialize(using Desen…...

JavaWeb学习打卡-Day5-Spring事务管理、SpringAOP

Spring事务管理 Transactional注解 位置&#xff1a;业务层&#xff08;Service&#xff09;的方法上、类上、接口上。作用&#xff1a;将当前方法交给spring进行事务管理&#xff0c;方法执行前&#xff0c;开启事务&#xff1b;成功执行完毕&#xff0c;提交事务&#xff1…...

项目立项管理

项目立项管理是对拟规划和实施的项目技术上的先进性、适用性&#xff0c;经济上的合理性、效益性&#xff0c;实施上的可能性、风险性以及社会价值的有效性、可持续性等进行全面科学的综合分析&#xff0c;为项目决策提供客观依据的一种技术经济研究活动。 一般包括项目建议与…...

一文梳理业财融合在财务管理中的运用!

目录 一、业财融合在财务管理中的运用概括 二、促进财务决策科学化 1. 传统财务决策的局限性 2. 业财融合助力财务决策科学化 三、加强成本控制 1. 传统成本控制的不足 2. 业财融合实现精准成本管控 四、优化资金管理 1. 传统资金管理的问题 2. 业财融合优化资金配置…...

C#核心知识

委托 如何声明一个委托&#xff1a;通过 【delegate 返回值类型 委托名称】 的格式来定义 如何使用一个委托&#xff1a;使用new关键字&#xff0c;并传入和声明委托的构造相同的方法名&#xff0c;比如&#xff1a;new 委托名称(与委托的参数和返回值相同的一个方法名) 如何…...

[多彩数据结构] 笛卡尔树

[多彩数据结构] 笛卡尔树 定义 笛卡尔树&#xff0c;就是一棵树&#xff08;废话&#xff09;中存两个信息&#xff0c;为 ( w , i ) (w,i) (w,i)。其中 k w e i g h t , i i d kweight,iid kweight,iid。 即 w w w 存的是节点的值&#xff0c; i i i 存的是编号。 每…...

【Spark入门】Spark RDD基础:转换与动作操作深度解析

目录 1 RDD编程模型概述 1.1 RDD操作分类 2 常用转换操作详解 2.1 基本转换操作 2.2 键值对转换操作 2.3 复杂转换操作 3 动作操作触发机制 3.1 常见动作操作 3.2 动作操作性能对比 4 RDD执行机制深度解析 4.1 惰性求值原理 4.2 任务生成过程 5 性能优化实践 5.1 …...

一文了解 模型上下文协议(MCP)

MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09;是由Anthropic公司于2024年11月推出的一项开放标准协议&#xff0c;旨在解决大型语言模型&#xff08;LLM&#xff09;与外部数据源和工具之间的通信问题。其核心目标是通过提供一个标准化的接口&…...

每日算法-250428

每日算法 - 2024年4月28日 记录今天完成的几道 LeetCode 算法题。 1877. 数组中最大数对和的最小值 题目描述: 思路 贪心策略。 解题过程 为了最小化所有数对和中的最大值&#xff0c;直观的想法是避免让两个较大的数相加。因此&#xff0c;最优策略是将数组中最小的元素…...

【“星瑞” O6 评测】 — CPU llama.cpp不同优化速度对比

前言 随着大模型应用场景的不断拓展&#xff0c;arm cpu 凭借其独特优势在大模型推理领域的重要性日益凸显。它在性能、功耗、架构适配等多方面发挥关键作用&#xff0c;推动大模型在不同场景落地 1. Kleidi AI 简介 Arm Kleidi 成为解决这些挑战的理想方案&#xff0c;它能…...

Redis 常见问题深度剖析与全方位解决方案指南

Redis 是一款广泛使用的开源内存数据库&#xff0c;在实际应用中常会遇到以下一些常见问题&#xff1a; 1.内存占用问题 问题描述&#xff1a;随着数据量的不断增加&#xff0c;Redis 占用的内存可能会超出预期&#xff0c;导致服务器内存不足&#xff0c;影响系统的稳定性和…...

在g2o图优化框架中,顶点(Vertex)和边(Edge)的定义与功能的区别

在g2o图优化框架中,顶点(Vertex)和边(Edge)是构建优化问题的核心组件,两者的定义与功能存在以下关键区别: 1. 作用与本质差异 顶点(Vertex) 代表待优化的变量,例如: 位姿(如VertexSE3Expmap表示3D位姿,包含平移和旋转)空间点坐标(如VertexPointXYZ表示3D点)参数…...

stm32wb55rg (2) 阅读资料手册

阅读资料是嵌入式开发的必备技能&#xff0c;能够从资料中找到自己想要的技术信息&#xff0c;才是最为核心的技术能力。 nucleowb55rg板子的MCU为stm32wb55rg&#xff0c;这块板子的资料有很多&#xff0c;但有些内容可以边用边读&#xff0c;有些内容有必要预先掌握下。 下面…...

基于Python的携程国际机票价格抓取与分析

一、项目背景与目标 携程作为中国领先的在线旅行服务平台&#xff0c;提供了丰富的机票预订服务。其国际机票价格受多种因素影响&#xff0c;包括季节、节假日、航班时刻等。通过抓取携程国际机票价格数据&#xff0c;我们可以进行价格趋势分析、性价比评估以及旅行规划建议等…...

【LLM开发】Unigram算法

Unigram算法 参考&#xff1a;Unigram算法解释 参考书籍&#xff1a;How Can We Make Language Models Better at Handling the Diversity and Variability of Natural Languages Unigram 算法是一种基于概率的子词分词方法&#xff0c;与BPE算法、WordPiece算法不同&#xff…...

GD32F407单片机开发入门(十六)单片机IAP(在应用编程)详解及实战源码

文章目录 一.概要二.GD32F407VET6单片机IAP介绍1.GD32F407VET6单片机IAP基本原理2.GD32F407VET6单片机IAP基本流程3.Ymodem协议 三.配置一个BOOT工程四.配置一个APP工程五.工程源代码下载六.小结 一.概要 单片机上电或系统复位后&#xff0c;ARM Cortex-M4处理器先从0x0000 00…...

庙算兵棋推演AI开发初探(7-神经网络训练与评估概述)

前面我们提取了特征做了数据集、设计并实现了处理数据集的神经网络&#xff0c;接下来我们需要训练神经网络了&#xff0c;就是把数据对接好灌进去&#xff0c;训练后查看预测的和实际的结果是否一致——也就是训练与评估。 数据解析提取 数据编码为数据集 设计神经网络 -->…...

[实战] IRIG-B协议详解及Verilog实现(完整代码)

目录 IRIG-B(B码)协议详解及Verilog实现一、IRIG-B协议概述二、帧格式详细解析1. 码元类型与索引计数2. 时间编码字段3. 控制功能码元&#xff08;CF&#xff09;4. 纯二进制秒码&#xff08;SBS&#xff09; 三、编码与信号特性四、时间编码实现1. 时间参数转换2. 帧数据填充规…...

从传统制造到智能工厂:MES如何重塑电子制造业?

在“中国制造2025”战略的引领下&#xff0c;电子制造业正经历深刻变革。多品种小批量、工艺复杂度高、质量追溯严苛等需求日益凸显。由此&#xff0c;如何通过数字化手段实现生产透明化、质量可追溯和资源高效协同&#xff0c;成为行业转型的关键命题。 一、电子制造业转型痛…...

使用Curl进行本地MinIO的操作

前言 最近在做相关的项目中关于本地服务搭建和访问的技术验证&#xff0c;打进来最基本的数据访问&#xff0c;使用了C。可以进行&#xff1a;服务器的可用性检查、Bucket的创建、文件夹的创建、文件的上传、文件的下载、文件夹和Bucket的存在性检查等基本接口&#xff0c;对自…...

uniswap getTickAtSqrtPrice 方法解析

先上代码&#xff1a; function getTickAtSqrtPrice(uint160 sqrtPriceX96) internal pure returns (int24 tick) {unchecked {// Equivalent: if (sqrtPriceX96 < MIN_SQRT_PRICE || sqrtPriceX96 > MAX_SQRT_PRICE) revert InvalidSqrtPrice();// second inequality mu…...

qemu(3) -- qemu-user使用

1. 前言 qemu中有很多的特技&#xff0c;此处记录下qemu-arm的使用方式&#xff0c;简单来说qemu-system-xx用于虚拟整个设备&#xff0c;包括操作系统的运行环境&#xff0c;而qemu-xx仅虚拟Linux应用程序的环境&#xff0c;不涉及操作系统&#xff0c;应用程序的系统调用有宿…...

CMCC RAX3000M使用Tftpd刷写OpenWrt固件的救砖方法

有时候&#xff0c;我们在玩运行 OpenWrt 的 CMCC RAX3000M &#xff0c;因为一些操作不当&#xff0c;导致无法进入路由器系统&#xff0c;无法正常刷机。此时&#xff0c;如果我们已经刷写了uboot&#xff0c;则可以在uboot模式下通过Tftpd刷写新的OpenWrt固件&#xff0c;实…...

Vue基础(7)_计算属性

计算属性(computed) 一、使用方式&#xff1a; 1.定义计算属性&#xff1a; 在Vue组件中&#xff0c;通过在 computed 对象中定义计算属性名称及对应的计算函数来创建计算属性。计算函数会返回计算属性的值。 2.在模板中使用计算属性&#xff1a; 在Vue的模板中&#xff0c;您…...

1.9多元函数积分学

引言 多元函数积分学是考研数学一的核心内容&#xff0c;涵盖三重积分、曲线积分、曲面积分及空间曲线积分。本文系统梳理4大考点&#xff0c;结合公式速查与典型示例&#xff0c;助你高效攻克积分难题&#xff01; 考点一&#xff1a;三重积分计算与应用 1️⃣ 对称性 (1) …...

【LINUX操作系统】线程操作

了解了线程的基本原理之后&#xff0c;我们来学习线程在C语言官方库中的写法与用法。 1. 常见pthread接口及其背后逻辑 1.1 pthread_create 与线程有关的函数构成了⼀个完整的系列&#xff0c;绝⼤多数函数的名字都是以“pthread_”打头的 • 要使⽤这些函数库&#xff0c;…...