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

.NET外挂系列:4. harmony 中补丁参数的有趣玩法(上)

一:背景

1. 讲故事

前面几篇我们说完了 harmony 的几个注入点,这篇我们聚焦注入点可接收的几类参数的解读,非常有意思,在.NET高级调试 视角下也是非常重要的,到底是哪些参数,用一张表格整理如下:

参数名说明
__instance访问非静态方法的实例(类似 this)。
__result获取/修改返回值,要想修改用 ref
__resultRef修改返回引用(方法返回是 ref 返回 )。
__state在前缀和后缀间传递自定义数据 。
___fields读写私有字段(三下划线开头,修改需加 ref)。
__argsobject[] 形式访问所有参数(修改数组即修改参数)。
方法参数同名直接映射原参数。
__n__n 表示直接访问第 n 个参数,从 0 开始)。
__originalMethod获取原方法的 MethodBase
__runOriginal判断原方法是否被执行。

大体上有10类参数,接下来开始介绍吧。

二:补丁参数解读

1. __instance

我们都知道 new Thread() 出来的线程默认都是 前台线程,而这种线程会阻塞程序的退出,所以需求就来了,能不能让 new Thread() 出来的线程自动变为后台线程呢?哈哈,这就需要借助 __instance 啦,我们对有参Start 方法进行注入, 参考代码如下:

internal class Program{static void Main(string[] args){var harmony = new Harmony("com.example.threadhook");harmony.PatchAll();var thread = new Thread((object obj) =>{var currentThread = Thread.CurrentThread;Console.WriteLine($"3. tid={currentThread.ManagedThreadId}, 线程内容为: {obj}, 是否为后台线程:{Thread.CurrentThread.IsBackground}");});Console.WriteLine($"1. new Thread() 完毕,当前是否为后台线程:{thread.IsBackground}");thread.Start("hello world!");Console.ReadLine();}}[HarmonyPatch(typeof(Thread), "Start", new Type[] { typeof(object) })]public class ThreadStartHook{public static void Prefix(Thread __instance){Console.WriteLine("----------------------------");Console.WriteLine($"2. 即将 Thread.Start: 线程tid={__instance.ManagedThreadId}");Console.WriteLine("----------------------------");// 将默认的 前台线程 改为 后台线程								__instance.IsBackground = true;}}

从卦中来看,非常完美,现在 Thread 再也不会阻塞程序的退出啦。。。

2. __state

有时候我们有这样的一个场景,想测量一个某个底层sdk方法的执行时间,更具体一点就是测量某个线程的执行时间,做法的话通常有两种。

  1. 在类中定义私有字段。

有些朋友可能知道 harmony 有这么一条规定,那就是xxxhook中的注入方法必须是 static,所以我们只能定义 static 类型的Dictionary字段来记录,有点尴尬,参考代码如下:

internal class Program{static void Main(string[] args){var harmony = new Harmony("com.example.threadhook");harmony.PatchAll();var thread = new Thread((object obj) =>{Thread.Sleep(new Random().Next(1000, 3000));var currentThread = Thread.CurrentThread;Console.WriteLine($"tid={currentThread.ManagedThreadId}, 线程内容为: {obj}");});thread.Start("hello world!");Console.ReadLine();}}[HarmonyPatch(typeof(Thread), "StartCallback")]public class ThreadStartHook{public static ConcurrentDictionary<int, Stopwatch> tidThreadTimeDict = new ConcurrentDictionary<int, Stopwatch>();public static void Prefix(Thread __instance){Console.WriteLine($"1. 正在测量线程的执行时间...");var watch = new Stopwatch();watch.Start();tidThreadTimeDict.TryAdd(__instance.ManagedThreadId, watch);}public static void Postfix(Thread __instance){var watch = tidThreadTimeDict[__instance.ManagedThreadId];watch.Stop();Console.WriteLine($"2. 线程执行结束,耗费时间:{watch.Elapsed.ToString()}");}}

从卦中可以看到当前线程执行了 1.58s,有点意思吧,针对上面的代码,有些朋友可能会挑毛病了。

  1. 实现过于繁琐。

确实有点繁琐,这时候就可以借助 __state 来充当 PerfixPostfix 之间的临时变量,同时要知道 __state 可以定义成任何类型。

  1. 我要看到方法,而不是线程

从卦中的输出看,确实我们要监控方法名,而不是线程,否则在真实场景中就会很乱,方法名我们从 Thread 下的 _startHelper 字段提取,这是一个匿名类,修改后的代码如下:

[HarmonyPatch(typeof(Thread), "StartCallback")]public class ThreadStartCallbackHook{public static void Prefix(Thread __instance, out (Stopwatch, string) __state){object startHelper = Traverse.Create(__instance).Field("_startHelper").GetValue();string methodName = Traverse.Create(startHelper).Field<Delegate>("_start").Value.Method.Name;object startArg = Traverse.Create(startHelper).Field("_startArg").GetValue();Console.WriteLine($"1. 正在测量 {methodName}({startArg}) 方法的执行时间...");var stopwatch = new Stopwatch();stopwatch.Start();__state = (stopwatch, $"{methodName}({startArg})");}public static void Postfix(Thread __instance, (Stopwatch, string) __state){var (stopwatch, methodName) = __state;Console.WriteLine($"2. 线程执行结束,{methodName} 耗费时间:{stopwatch.Elapsed.ToString()}");}}

哈哈,修改后的代码相比第一版是不是爽了很多。。。

3. __originalMethod

这个参数也是蛮重要的,通过它可以让你知道当前 patch 正骑在哪个原方法上,起到了过滤识别的作用,参考代码如下:

internal class Program{static void Main(string[] args){var harmony = new Harmony("com.example.threadhook");harmony.PatchAll();var max = Math.Max(10, 20);Console.ReadLine();}}[HarmonyPatch(typeof(Math), "Max", new Type[] { typeof(int), typeof(int) })]public class ThreadStartCallbackHook{public static void Prefix(Thread __instance, MethodBase __originalMethod){var parameters = string.Join(",", __originalMethod.GetParameters().Select(i => i.Name));Console.WriteLine($"当前 Prefix 正在处理 {__originalMethod.Name}({parameters}) 方法...");}}

三:总结

灵活运用这些奇奇怪怪的参数,相信你对 harmony 的使用有了一个全新的认识,大家可以开开心心的投放生产吧,去解决那些 Windows,Linux 上的 .NET程序的疑难杂症。

相关文章:

.NET外挂系列:4. harmony 中补丁参数的有趣玩法(上)

一&#xff1a;背景 1. 讲故事 前面几篇我们说完了 harmony 的几个注入点&#xff0c;这篇我们聚焦注入点可接收的几类参数的解读&#xff0c;非常有意思&#xff0c;在.NET高级调试 视角下也是非常重要的&#xff0c;到底是哪些参数&#xff0c;用一张表格整理如下&#xff…...

【VLNs篇】03:VLMnav-端到端导航与视觉语言模型:将空间推理转化为问答

栏目内容论文标题End-to-End Navigation with Vision-Language Models: Transforming Spatial Reasoning into Question-Answering (端到端导航与视觉语言模型&#xff1a;将空间推理转化为问答)核心问题如何利用大型视觉语言模型&#xff08;VLM&#xff09;实现端到端的机器人…...

云原生攻防4(Kubernetes基础补充)

什么是K8S? Kubernetes 是做什么的? 什么是 Docker? 什么是容器编排? Kubernetes 一词来自希腊语,意思是“飞行员”或“舵手”。这个名字很贴切,Kubernetes 可以帮助你在波涛汹涌的容器海洋中航行。 Kubernetes 是 Google 基于 Borg 开源的容器编排调度引擎,作为 CNCF最…...

redis--redisJava客户端:Jedis详解

在Redis官网中提供了各种语言的客户端&#xff0c;地址&#xff1a; https://redis.io/docs/latest/develop/clients/ Jedis 以Redis命令做方法名称&#xff0c;学习成本低&#xff0c;简单实用&#xff0c;但是对于Jedis实例是线程不安全的&#xff08;即创建一个Jedis实例&a…...

SpringBoot-SpringBoot源码解读

SpringBoot-SpringBoot源码解读 一、Spring Boot启动过程概述 Spring Boot通过一系列的类和机制&#xff0c;简化了Spring应用的启动流程。当你执行SpringApplication.run()时&#xff0c;Spring Boot会自动完成应用的初始化、环境配置、组件加载、自动配置等任务&#xff0c…...

黑马程序员C++2024新版笔记 第4章 函数和结构体

1.结构体的基本应用 结构体struct是一种用户自定义的复合数据类型&#xff0c;可以包含不同类型的成员。例如&#xff1a; struct Studet {string name;int age;string gender; } 结构体的声明定义和使用的基本语法&#xff1a; struct 结构体类型 {成员1类型 成员1名称;成…...

【沉浸式求职学习day46】【华为5.7暑期机试题目讲解】

沉浸式求职学习 题目1题目2 题目1 一个超大智能汽车测试场有多个充电桩&#xff0c;每个充电桩的位置由其在二维平面上的坐标(x,y)表示。给定一辆智能汽车的当前位置(car_x,car_y)&#xff0c;请设计一个高效的算法&#xff0c;找出给定智能汽车行驶到充电桩行驶距离最近的k个…...

PDF处理控件Aspose.PDF教程:以编程方式将PDF转换为Word

您是否正在寻找在线将 PDF 转换为 Word 的方法&#xff1f;在本指南中&#xff0c;我们将探索如何使用 C#、Java 和 Python 编码解决方案将 PDF 文档转换为可编辑的 Word 文件。开发人员通过代码将 PDF 文件转换为 Word 格式&#xff0c;从而获得显著优势。这种方法可以轻松实现…...

旋转位置RoPE编码详解

一. 旋转位置编码和正余弦位置编码比对 旋转位置编码&#xff08;RoPE&#xff09;和正余弦位置编码&#xff08;Sinusoidal Position Encoding&#xff09;是两种常用的位置编码方法&#xff0c;它们在处理序列数据时具有不同的数学形式和特性。以下是对两者优劣的详细说明及…...

canvas(二)-动画(2d)

<canvas> 动画是通过 JavaScript 动态更新画布内容来实现的。它利用 requestAnimationFrame 方法实现平滑的动画效果&#xff0c;适用于游戏、数据可视化、交互式图形等场景。真的需要数据可视化等场景使用&#xff0c;还是直接引入外部模型还原度比较高&#xff0c;但同…...

Dynamics 365 Business Central Azure application registration

本方法适用于 单租户服务器身份验证。 实现方法 在大多数组织里ERP Admin 不一定有权限 Azure Admin权限&#xff0c;在实施过程中你只需要把以下指引发给你的系统管理员。 请注意后面有系统管理员设置好后&#xff0c;你如何检查。 导航到 https://admin.microsoft.com 并登…...

选择合适的Azure数据库监控工具

Azure云为组织提供了众多服务&#xff0c;使其能够无缝运行应用程序、Web服务和服务器部署&#xff0c;其中包括云端数据库部署。Azure数据库能够与云应用程序实现无缝集成&#xff0c;具备可靠、易扩展和易管理的特性&#xff0c;不仅能提升数据库可用性与性能&#xff0c;同时…...

Access链接Azure SQL

Hi&#xff0c;大家好呀&#xff01; 最近在给大家分享了SQL Server方面的一些视频&#xff0c;那今天我们也来讲讲Azure SQL。 什么是Azure SQL&#xff0c;这里我们就不介绍了&#xff0c;如果你没有用这个数据库&#xff0c;那你可以简单的把它理解成&#xff0c;就是SQL …...

34、React Server Actions深度解析

一、灵魂契约协议&#xff08;核心机制&#xff09; 1. 次元融合架构 "use server";async function borrowBook(bookId: number, readerName: string) {// 模拟数据库操作const result await db.execute(UPDATE books SET available false WHERE id ?,[bookId]…...

Azure 应用服务中的异常处理、日志记录和通知:综合指南

简介 Azure 应用服务是基于云的应用程序&#xff0c;使开发人员能够在云上构建、部署和管理应用程序。与任何应用程序一样&#xff0c;制定适当的异常处理、日志记录和通知实践至关重要&#xff0c;以确保应用程序平稳运行&#xff0c;并快速识别和解决任何问题。在本篇博文中&…...

第16天-使用Python Pillow库常见图像处理场景

1. 打开与显示图像 from PIL import Image# 打开图像文件 img = Image.open("input.jpg")# 显示图像基本信息 print(f"格式: {img.format}") # JPEG print(f"尺寸: {img.size}") # (宽度, 高度) print(f"模式: {img.mode}") …...

VUE3+TS实现图片缩放移动弹窗

完整代码 使用VUE3、TS&#xff0c;实现将图片通过鼠标拖拽缩放以及选择缩放比例。 <template><div><el-dialogv-model"dialogVisible"title"查看图片":close-on-click-modal"false":close-on-press-escape"false"fu…...

关于Vue自定义组件封装的属性/事件/插槽的透传问题

// parent.vue <Myinputv-model"keyWords"placeholder"请输入内容"size"small"input"input"change"change"width"320" ><template #prepend><el-select v-model"select" placeholder&qu…...

智能驾驶中的深度学习:基于卷积神经网络的车道线检测

摘要 智能驾驶是人工智能技术的重要应用领域之一,而车道线检测是实现自动驾驶的基础功能。本文介绍了一种基于深度学习的车道线检测方法,使用卷积神经网络(CNN)对道路图像进行实时分析。文章详细阐述了数据预处理、模型构建、训练优化及实际部署的完整流程,并提供了Pytho…...

在 Excel xll 自动注册操作 中使用东方仙盟软件2————仙盟创梦IDE

// 获取当前工作表名称string sheetName (string)XlCall.Excel(XlCall.xlfGetDocument, 7);// 构造动态名称&#xff08;例如&#xff1a;Sheet1!MyNamedCell&#xff09;string fullName $"{sheetName}!MyNamedCell";// 获取引用并设置值var namedRange (ExcelRe…...

【每周一个MCP】:将pytdx封装成MCP

文章目录 配置文件MCP代码(其实github上都有)不错不错,星星之火可以燎原。 https://github.com/ddholiday/onedayoneMCP/tree/main/MCPs/tdx-mcp 配置文件 pytdx有两种读取数据的方式,分别是,从API读取,和从本地读取。 其中,从API读取,需要IP和端口。 这个官方文档…...

Vue3中插槽, pinia的安装和使用(超详细教程)

1. 插槽 插槽是指, 将一个组件的代码片段, 引入到另一个组件。 1.1 匿名插槽 通过简单的案例来学习匿名插槽&#xff0c;案例说明&#xff0c;在父组件App.vue中导入了子组件Son1.vue&#xff0c;父组件引用子组件的位置添加了一个片段&#xff0c;比如h2标签&#xff0c;然…...

【Java高阶面经:微服务篇】5.限流实战:高并发系统流量治理全攻略

一、限流阈值的三维度计算模型 1.1 系统容量基准线:压测驱动的安全水位 1.1.1 压力测试方法论 测试目标:确定系统在资源安全水位(CPU≤80%,内存≤70%,RT≤500ms)下的最大处理能力测试工具: 单机压测:JMeter(模拟10万并发)、wrk(低资源消耗)集群压测:LoadRunner …...

学习黑客了解密码学

5分钟了解密码学&#xff1a;从古老艺术到现代科学 &#x1f510; 作者: 海尔辛 | 发布时间: 2025-05-21 08:36:35 UTC 密码学简介&#xff1a;保护信息的艺术与科学 &#x1f4dc; 密码学是研究如何安全传递和存储信息的学科。它不仅仅是加密和解密&#xff0c;更包含了身份…...

【UE5】环形菜单教程

效果 步骤 1. 下载图片资源&#xff1a;百度网盘 请输入提取码 提取码:fjjx 2. 将图片资源导入工程&#xff0c;如下 3. 新建3个控件蓝图&#xff0c;这里分别命名为“WBP_CircularMenu”、“WBP_Highlight”、“WBP_Icon” 4. 打开“WBP_Icon”&#xff0c;设置“所需” 添加…...

【JVM】学习笔记

1. JVM概述 JVM是一个抽象的计算机&#xff0c;用于运行Java程序。它将Java字节码转化为特定平台的机器代码&#xff0c;确保Java程序具有跨平台性。 2. JVM架构 JVM的架构通常包括以下几个主要部分&#xff1a; 类加载子系统&#xff08;ClassLoader&#xff09;&#xff…...

物流项目第五期(运费计算实现、责任链设计模式运用)

前四期&#xff1a; 物流项目第一期&#xff08;登录业务&#xff09;-CSDN博客 物流项目第二期&#xff08;用户端登录与双token三验证&#xff09;-CSDN博客 物流项目第三期&#xff08;统一网关、工厂模式运用&#xff09;-CSDN博客 物流项目第四期&#xff08;运费模板列…...

PrintStream PrintWriter Java 打印流

使用场景​&#xff1a; 代替 System.out 输出日志&#xff08;比如 System.setOut(printStream)&#xff09;需要输出各种类型&#xff08;如 println(123)、println("hello")&#xff09; 常用方法​&#xff1a; print(), println() → 支持所有基本类型和对象pr…...

前端excel表格解析为json,并模仿excel显示

前端环境&#xff1a;elementUI vue2 <style lang"scss" scoped> 页面效果 jsondata为mock数据&#xff0c;为方便调试其内容可清空&#xff0c;首行&#xff08;字母坐标&#xff09;随数据内容自动变化&#xff0c;首列也是一样&#xff0c;模拟excel …...

NumPy 2.x 完全指南【十六】分割数组

文章目录 1. 数组分割1.1 split1.2 array_split1.3 vsplit1.4 hsplit1.5 dsplit1.6 unstack 1. 数组分割 数组分割是指将一个数组拆分为多个子数组的操作&#xff0c;常用于数据处理、并行计算、分块处理等场景。NumPy 提供了多种分割函数&#xff0c;允许用户沿不同方向&…...

vue3 + vite 使用tailwindcss

第一步&#xff1a;安装依赖 vite版本较低&#xff08;“vite”: “^4.0.0”&#xff09;所以就使用低版本的tailwindcss npm install -D tailwindcss3.4.1 postcss autoprefixer第二步&#xff1a;配置文件生成 npx tailwindcss init -p会自动生成两个文件postcss.config.js和…...

K个一组链表翻转

目录 1. 题意 2. 解题思路 3. 代码 1. 题意 给一个链表&#xff0c;按 k 进行翻转&#xff0c;也就是 k 2 &#xff0c;两两进行翻转&#xff0c;如果不够2则不动。 2. 解题思路 首先思考怎么翻转一个链表&#xff0c;反转链表&#xff1a;https://leetcode.cn/problems…...

逆向音乐APP:Python爬虫获取音乐榜单 (1)

1. 引言 在数字音乐时代&#xff0c;许多平台如音乐有榜单&#xff0c;限制非付费用户访问高音质或独家内容。然而&#xff0c;从技术研究的角度来看&#xff0c;我们可以通过逆向工程和Python爬虫技术解音乐的API接口&#xff0c;获取付费音乐的播放链接。 2. 技术准备 在当…...

STM32之串口通信WIFI上云

一、W模块的原理与应用 基本概念 如果打算让硬件设备可以通过云服务器进行通信&#xff08;数据上报/指令下发&#xff09;&#xff0c;像主流的云服务器有阿里云、腾讯云、华为云&#xff0c;以及其他物联网云平台&#xff1a;巴法云.......&#xff0c;硬件设备需要通过TCP…...

Python爬虫实战:获取天气网最近一周北京的天气数据,为日常出行做参考

1. 引言 随着互联网技术的发展,气象数据的获取与分析已成为智慧城市建设的重要组成部分。天气网作为权威的气象信息发布平台,其数据具有较高的准确性和实时性。然而,人工获取和分析天气数据效率低下,无法满足用户对精细化、个性化气象服务的需求。本文设计并实现了一套完整…...

【Java学习笔记】main方法

main 方法 一、深入理解 main 方法 特变注意&#xff01;&#xff01; 1. 在main()方法中&#xff0c;我们可以直接调用 mian 方法所在类的静态方法或静态属性 2. 不能访问该类中的非静态成员&#xff0c;必须创建该类的一个实例对象后&#xff0c;才能通过这个对象去访问类中…...

振动分析 - 献个宝

1.一个自制的振动能量分析工具 这个分析工具似乎真的定位到了故障的具体位置。 1.1对一组实验室虚拟信号的分析结果: 1.2 对现场真实数据的分析结果 依照边频带的调制,和边频的缝隙宽度,基本定位到问题。 追加几份待看的文档: 齿轮结构的频谱特征 - 知乎使用 FFT 获得…...

数学实验(Matlab绘图基础)

一、二维曲线的绘制 Matlab绘图原理 MATLAB绘图的核心原理基于数据点或函数离散化&#xff0c;通过描点连线生成图形。以下是具体解析&#xff1a; 1.数据离散化 二维数据通过&#xff08;x, y&#xff09;坐标点表示&#xff0c;连续函数需离散化处理&#xff08;如t0:0.01…...

【android bluetooth 协议分析 02】【bluetooth hal 层详解 3】【高通蓝牙hal主要流程介绍-上】

1. 背景 本节主要讨论 高通 蓝牙 hal 中&#xff0c;的一些流程。 看看你是否都清楚如下问题&#xff1a; 高通芯片电如何控制&#xff1f;串口是在哪里控制的&#xff1f;固件如何下载&#xff1f;初始化流程是怎么样的&#xff1f; 如果你已经对上述讨论的问题&#xff0c…...

Linux | tmux | 无法复制粘贴

问题&#xff1a;在Linux中使用tmux时&#xff0c;总是没法使用复制粘贴功能&#xff1b; 解决: 如果希望直接用鼠标选择并复制&#xff08;类似普通终端&#xff09;&#xff0c;可以&#xff1a; 在 ~/.tmux.conf 中添加&#xff1a;sh set -g mouse on;重新加载 tmux 配置…...

如何通过小贝加速实现精准网络故障排查

在日常使用电脑的过程中&#xff0c;我们常常需要监控系统运行状态、优化性能或排查网络问题。最近发现一款名为小贝加速的桌面工具&#xff0c;在此分享关于小贝加速如何实现网络监控。 系统优化 该工具提供了简洁明了的系统优化功能。通过扫描可以清理系统冗余文件、释放内存…...

Nginx 网站服务

目录 一&#xff1a;基于授权的访问控制 1&#xff1a;基于授权的访问控制简介 2&#xff1a;基于授权的访问控制步骤 二&#xff1a;基于客户端的访问控制 1&#xff1a;基于客户端的访问控制简介 2&#xff1a;基于客户端的访问控制步骤 三&#xff1a;Nginx 虚拟主机…...

Python 字典的用法和技巧

字典的创建与初始化 Python 字典是一种可变容器模型&#xff0c;可存储任意类型对象。字典的每个键值对用冒号分隔&#xff0c;键值对之间用逗号分隔&#xff0c;整个字典包括在花括号中。 # 创建一个空字典 empty_dict {}# 创建一个包含键值对的字典 my_dict {name: Alice…...

电力设备制造企业数字化转型路径研究:从生产优化到生态重构

电力设备制造业作为支撑能源革命的核心领域&#xff0c;其数字化转型不仅关乎企业降本增效&#xff0c;更是实现“双碳”目标与新型电力系统建设的关键抓手。本文基于行业标杆案例与实践经验&#xff0c;系统梳理电力设备企业数字化转型的五大核心路径。 一、生产流程智能化&a…...

初识GPU加速:如何利用GPU提升AI训练效率

随着人工智能(AI)和深度学习技术的快速发展,训练深度神经网络(DNN)已经变得越来越复杂和计算密集。传统的CPU已经无法满足大量计算任务的需求,因此,GPU(图形处理单元)成为了训练深度学习模型时的必备工具。本篇文章将介绍如何利用GPU加速AI训练效率,以及在使用GPU时应…...

深入解析异步编程:Java NIO、Python `async/await` 与 C# `async/await` 的对比

在现代编程中&#xff0c;异步编程已成为处理 I/O 密集型任务&#xff08;如网络请求、文件操作等&#xff09;的高效方式。不同的编程语言提供了各自的异步编程模型&#xff0c;以提高程序的性能和资源利用率。本文将深入解析 Java 的 NIO、Python 的 async/await 和 C# 的 as…...

阿里云数据盘级别

数据盘PL0、PL1、PL2和PL3的区别体现在性能、容量范围以及应用场景等方面。具体分析如下&#xff1a; 性能 PL0&#xff1a;单盘最大IOPS为10,000&#xff0c;最大吞吐量为180MB/s。适用于中小型MySQL和SQLServer等数据库场景&#xff0c;中小规模ELK日志集群&#xff0c;SAP和…...

使用 Spring AI Alibaba 集成阿里云百炼大模型应用

随着人工智能技术的飞速发展&#xff0c;大模型在各个领域的应用越来越广泛。阿里云百炼大模型提供了强大的语言理解和生成能力&#xff0c;但如何将其高效地集成到实际应用中&#xff0c;一直是开发者关注的焦点。本文将详细介绍如何使用 Spring AI Alibaba 集成阿里云百炼大模…...

阿里云合集(不定期更新)

一、阿里云申请免费域名证书流程&#xff1a;https://blog.csdn.net/humors221/article/details/143266059 二、阿里云发送国内短信怎样编程&#xff1a;https://blog.csdn.net/humors221/article/details/139544193 三、阿里云ECS服务器磁盘空间不足的几个文件&#xff1a;h…...

零基础设计模式——创建型模式 - 抽象工厂模式

第二部分&#xff1a;创建型模式 - 抽象工厂模式 (Abstract Factory Pattern) 我们已经学习了单例模式&#xff08;保证唯一实例&#xff09;和工厂方法模式&#xff08;延迟创建到子类&#xff09;。现在&#xff0c;我们来探讨创建型模式中更为复杂和强大的一个——抽象工厂…...