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

工程化与框架系列(35)--前端微服务架构实践

前端微服务架构实践 🏗️

引言

随着前端应用规模的不断扩大,微服务架构在前端领域的应用越来越广泛。本文将深入探讨前端微服务架构的实现方案、最佳实践和相关工具。

微服务架构概述

前端微服务架构主要包括以下方面:

  • 应用拆分:基于业务域的应用拆分策略
  • 独立部署:各个微应用的独立开发、构建和部署
  • 运行时集成:微应用的加载、通信和生命周期管理
  • 共享资源:公共依赖、组件库、工具函数等的共享策略
  • 统一管理:路由、状态、权限等的统一管理方案

微服务架构实现

微前端容器

// 微前端容器类
class MicroFrontendContainer {private static instance: MicroFrontendContainer;private apps: Map<string, MicroApp>;private config: ContainerConfig;private constructor() {this.apps = new Map();this.config = {sandbox: true,prefetch: true,isolation: 'iframe',timeout: 3000};}// 获取单例实例static getInstance(): MicroFrontendContainer {if (!MicroFrontendContainer.instance) {MicroFrontendContainer.instance = new MicroFrontendContainer();}return MicroFrontendContainer.instance;}// 注册微应用registerApp(appConfig: MicroAppConfig): void {const app = new MicroApp(appConfig);this.apps.set(appConfig.name, app);// 预加载配置if (this.config.prefetch) {this.prefetchApp(app);}}// 启动微应用async startApp(name: string): Promise<void> {const app = this.apps.get(name);if (!app) {throw new Error(`App ${name} not found`);}try {// 加载微应用资源await this.loadApp(app);// 创建沙箱环境const sandbox = this.createSandbox(app);// 挂载微应用await this.mountApp(app, sandbox);// 初始化通信this.initCommunication(app);} catch (error) {console.error(`Failed to start app ${name}:`, error);throw error;}}// 停止微应用async stopApp(name: string): Promise<void> {const app = this.apps.get(name);if (!app) {throw new Error(`App ${name} not found`);}try {// 卸载微应用await this.unmountApp(app);// 清理沙箱this.cleanupSandbox(app);// 清理资源this.cleanupResources(app);} catch (error) {console.error(`Failed to stop app ${name}:`, error);throw error;}}// 预加载微应用private async prefetchApp(app: MicroApp): Promise<void> {try {const resources = await this.loadResources(app.config.entry);app.setResources(resources);} catch (error) {console.warn(`Failed to prefetch app ${app.config.name}:`, error);}}// 加载微应用资源private async loadApp(app: MicroApp): Promise<void> {if (app.isLoaded()) {return;}const resources = app.getResources() || await this.loadResources(app.config.entry);await this.injectResources(resources);app.setLoaded(true);}// 加载资源private async loadResources(entry: string): Promise<AppResources> {const response = await fetch(entry);const html = await response.text();return {scripts: this.extractScripts(html),styles: this.extractStyles(html),templates: this.extractTemplates(html)};}// 注入资源private async injectResources(resources: AppResources): Promise<void> {// 注入样式await Promise.all(resources.styles.map(style => this.loadStyle(style)));// 注入脚本await Promise.all(resources.scripts.map(script => this.loadScript(script)));}// 创建沙箱环境private createSandbox(app: MicroApp): Sandbox {if (this.config.isolation === 'iframe') {return new IframeSandbox(app);} else {return new JsSandbox(app);}}// 挂载微应用private async mountApp(app: MicroApp,sandbox: Sandbox): Promise<void> {const mountPoint = document.querySelector(app.config.container);if (!mountPoint) {throw new Error(`Mount point ${app.config.container} not found`);}// 执行生命周期钩子await app.beforeMount();// 在沙箱中执行挂载await sandbox.mount(mountPoint);// 更新应用状态app.setMounted(true);// 执行生命周期钩子await app.afterMount();}// 卸载微应用private async unmountApp(app: MicroApp): Promise<void> {if (!app.isMounted()) {return;}// 执行生命周期钩子await app.beforeUnmount();// 移除DOMconst container = document.querySelector(app.config.container);if (container) {container.innerHTML = '';}// 更新应用状态app.setMounted(false);// 执行生命周期钩子await app.afterUnmount();}// 清理沙箱private cleanupSandbox(app: MicroApp): void {const sandbox = app.getSandbox();if (sandbox) {sandbox.cleanup();}}// 清理资源private cleanupResources(app: MicroApp): void {const resources = app.getResources();if (resources) {// 移除样式resources.styles.forEach(style => {const element = document.querySelector(`link[href="${style}"]`);element?.remove();});// 移除脚本resources.scripts.forEach(script => {const element = document.querySelector(`script[src="${script}"]`);element?.remove();});}}// 初始化应用间通信private initCommunication(app: MicroApp): void {const eventBus = EventBus.getInstance();// 注册应用通信处理器app.setMessageHandler(message => {eventBus.emit(`${app.config.name}:message`, message);});// 监听其他应用消息this.apps.forEach(otherApp => {if (otherApp !== app) {eventBus.on(`${otherApp.config.name}:message`,message => {app.postMessage(message);});}});}
}// 微应用类
class MicroApp {private loaded: boolean = false;private mounted: boolean = false;private resources: AppResources | null = null;private sandbox: Sandbox | null = null;private messageHandler: MessageHandler | null = null;constructor(public config: MicroAppConfig) {}// 生命周期钩子async beforeMount(): Promise<void> {await this.invokeLifecycle('beforeMount');}async afterMount(): Promise<void> {await this.invokeLifecycle('afterMount');}async beforeUnmount(): Promise<void> {await this.invokeLifecycle('beforeUnmount');}async afterUnmount(): Promise<void> {await this.invokeLifecycle('afterUnmount');}// 调用生命周期函数private async invokeLifecycle(name: string): Promise<void> {const lifecycle = (window as any)[`${this.config.name}:${name}`];if (typeof lifecycle === 'function') {await lifecycle();}}// 状态管理isLoaded(): boolean {return this.loaded;}setLoaded(loaded: boolean): void {this.loaded = loaded;}isMounted(): boolean {return this.mounted;}setMounted(mounted: boolean): void {this.mounted = mounted;}// 资源管理getResources(): AppResources | null {return this.resources;}setResources(resources: AppResources): void {this.resources = resources;}// 沙箱管理getSandbox(): Sandbox | null {return this.sandbox;}setSandbox(sandbox: Sandbox): void {this.sandbox = sandbox;}// 消息通信setMessageHandler(handler: MessageHandler): void {this.messageHandler = handler;}postMessage(message: any): void {this.messageHandler?.(message);}
}// 沙箱基类
abstract class Sandbox {constructor(protected app: MicroApp) {}abstract mount(container: Element): Promise<void>;abstract cleanup(): void;
}// iframe沙箱
class IframeSandbox extends Sandbox {private iframe: HTMLIFrameElement | null = null;async mount(container: Element): Promise<void> {this.iframe = document.createElement('iframe');this.iframe.src = 'about:blank';this.iframe.style.width = '100%';this.iframe.style.height = '100%';this.iframe.style.border = 'none';container.appendChild(this.iframe);// 注入资源到iframeawait this.injectResources();}cleanup(): void {this.iframe?.remove();this.iframe = null;}private async injectResources(): Promise<void> {if (!this.iframe) return;const resources = this.app.getResources();if (!resources) return;const doc = this.iframe.contentDocument;if (!doc) return;// 注入样式resources.styles.forEach(style => {const link = doc.createElement('link');link.rel = 'stylesheet';link.href = style;doc.head.appendChild(link);});// 注入脚本for (const script of resources.scripts) {await new Promise((resolve, reject) => {const scriptElement = doc.createElement('script');scriptElement.src = script;scriptElement.onload = resolve;scriptElement.onerror = reject;doc.head.appendChild(scriptElement);});}}
}// JS沙箱
class JsSandbox extends Sandbox {private proxy: Window | null = null;async mount(container: Element): Promise<void> {// 创建代理对象this.proxy = new Proxy(window, {get: (target, property) => {// 处理特殊属性if (this.isProtected(property)) {return target[property as keyof Window];}// 返回沙箱中的值return (this.app as any)[property];},set: (target, property, value) => {// 禁止修改保护属性if (this.isProtected(property)) {return false;}// 设置值到沙箱(this.app as any)[property] = value;return true;}});// 在沙箱环境中执行代码this.executeInSandbox(() => {const resources = this.app.getResources();if (!resources) return;// 执行脚本resources.scripts.forEach(script => {const scriptElement = document.createElement('script');scriptElement.src = script;container.appendChild(scriptElement);});});}cleanup(): void {this.proxy = null;}private executeInSandbox(code: Function): void {if (!this.proxy) return;// 保存原始windowconst originalWindow = window;// 替换为代理对象(window as any) = this.proxy;try {// 执行代码code();} finally {// 恢复原始window(window as any) = originalWindow;}}private isProtected(property: string | symbol): boolean {// 保护的全局属性列表const protectedProps = ['window','document','location','history'];return protectedProps.includes(property.toString());}
}// 事件总线
class EventBus {private static instance: EventBus;private handlers: Map<string, Set<Function>>;private constructor() {this.handlers = new Map();}static getInstance(): EventBus {if (!EventBus.instance) {EventBus.instance = new EventBus();}return EventBus.instance;}on(event: string, handler: Function): void {if (!this.handlers.has(event)) {this.handlers.set(event, new Set());}this.handlers.get(event)?.add(handler);}off(event: string, handler: Function): void {this.handlers.get(event)?.delete(handler);}emit(event: string, data?: any): void {this.handlers.get(event)?.forEach(handler => {handler(data);});}
}// 接口定义
interface ContainerConfig {sandbox: boolean;prefetch: boolean;isolation: 'iframe' | 'js';timeout: number;
}interface MicroAppConfig {name: string;entry: string;container: string;props?: Record<string, any>;
}interface AppResources {scripts: string[];styles: string[];templates: string[];
}type MessageHandler = (message: any) => void;// 使用示例
const container = MicroFrontendContainer.getInstance();// 注册微应用
container.registerApp({name: 'app1',entry: 'http://localhost:3001',container: '#app1'
});container.registerApp({name: 'app2',entry: 'http://localhost:3002',container: '#app2'
});// 启动微应用
await container.startApp('app1');// 停止微应用
await container.stopApp('app1');

最佳实践与建议

  1. 应用拆分

    • 基于业务域划分
    • 合理粒度
    • 独立演进
    • 技术栈灵活
  2. 依赖管理

    • 共享依赖
    • 版本控制
    • 构建优化
    • 运行时加载
  3. 通信机制

    • 事件总线
    • 状态共享
    • 数据隔离
    • 安全控制
  4. 部署策略

    • 独立部署
    • 灰度发布
    • 版本控制
    • 回滚机制

总结

前端微服务架构需要考虑以下方面:

  1. 应用拆分和集成策略
  2. 资源加载和性能优化
  3. 应用通信和状态管理
  4. 部署和运维支持
  5. 开发和协作流程

通过合理的微服务架构设计,可以提高前端应用的可维护性和扩展性。

学习资源

  1. 微前端架构设计
  2. 模块联邦实践
  3. 沙箱隔离方案
  4. 性能优化指南
  5. 部署运维实践

如果你觉得这篇文章有帮助,欢迎点赞收藏,也期待在评论区看到你的想法和建议!👇

终身学习,共同成长。

咱们下一期见

💻

相关文章:

工程化与框架系列(35)--前端微服务架构实践

前端微服务架构实践 &#x1f3d7;️ 引言 随着前端应用规模的不断扩大&#xff0c;微服务架构在前端领域的应用越来越广泛。本文将深入探讨前端微服务架构的实现方案、最佳实践和相关工具。 微服务架构概述 前端微服务架构主要包括以下方面&#xff1a; 应用拆分&#xf…...

多条件下的免杀webshell

前言 在做webshell免杀的时候&#xff0c;很多情况下都是对system,eval等命令执行函数进行匹配&#xff0c;如果说把变量当做一个函数来使用的话&#xff0c;那是不是可以bypass了呢&#xff1f;这今天刚好看见有一个回调函数有这样的功能&#xff0c;而且也不会报毒&#xff…...

【算法】动态规划

⭐️个人主页&#xff1a;小羊 ⭐️所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 动态规划总结1、常见动态规划Fibonacci数列杨辉三角最小花费爬楼梯孩子们的游戏 2、组合方案李白打酒加强版&#xff08;lqb&…...

MySQL事务及索引复习笔记

本文参考小林coding&#xff0c;地址事务隔离级别是怎么实现的&#xff1f; | 小林coding 事务 一、事务是什么&#xff1f; 比如一个程序是转账&#xff0c;你要扣减a的余额&#xff0c;增加b的余额&#xff0c;但是如果程序执行扣减成功然后挂了&#xff0c;就会出现a的余额…...

API调用大模型推理与第三方API实现业务整合

基于Python实现大模型推理与第三方API调用的集成&#xff0c;需要结合Function Call机制与提示词工程。 一、技术架构设计 双阶段流程 推理阶段&#xff1a;大模型解析用户意图&#xff0c;生成结构化API调用指令执行阶段&#xff1a;Python代码解析指令并触发第三方API # 示例…...

GreenKGC: A Lightweight Knowledge Graph Completion Method(论文笔记)

CCF等级&#xff1a;A 发布时间&#xff1a;2023年7月 代码位置 25年3月17日交 目录 一、简介 二、原理 1.整体 2.表示学习 3.特征修剪 4.决策学习 三、实验性能 1.主要结果 2.消融实验 四、结论和未来工作 一、简介 传统知识图谱补全方法中&#xff0c;嵌入维度…...

Android Composable 与 View 的联系和区别

在 Android 开发中&#xff0c;‌Composable‌&#xff08;Jetpack Compose&#xff09;与‌View‌&#xff08;传统 View 系统&#xff09;是两种不同的 UI 构建范式。本文将从核心联系、核心区别、代码实现三方面展开对比&#xff0c;并通过实例代码帮助开发者理解其应用场景…...

微信小程序wx.request接口报错(errno: 600001, errMsg: “request:fail -2:net::ERR_FAILED“)

来看看报错 报错如下: 请求发送部分,代码如下: uni.request({url: self.serverUrl "/getRealName",method: GET,data: {"code": self.info.code,},header: {"Authorization": uni.getStorageSync(tokenHead) uni.getStorageSync(token)}}…...

多线程与并发编程 面试专题

多线程与并发编程 面试专题 线程的基础概念基础概念线程的创建线程的状态线程的终止方式start 与 run 区别线程的常用方法 锁锁的分类深入synchronized深入ReentrantLock死锁问题 阻塞队列线程池 线程的基础概念 基础概念 进程与线程 进程&#xff1a;指运行中的程序。 比如我…...

大语言模型-1.2-大模型技术基础

简介 本博客内容是《大语言模型》一书的读书笔记&#xff0c;该书是中国人民大学高瓴人工智能学院赵鑫教授团队出品&#xff0c;覆盖大语言模型训练与使用的全流程&#xff0c;从预训练到微调与对齐&#xff0c;从使用技术到评测应用&#xff0c;帮助学员全面掌握大语言模型的…...

【C++】每日一练(轮转数组)

本篇博客给大家带来的是用C语言来解答轮转数组&#xff01; &#x1f41f;&#x1f41f;文章专栏&#xff1a;每日一练 &#x1f680;&#x1f680;若有问题评论区下讨论&#xff0c;我会及时回答 ❤❤欢迎大家点赞、收藏、分享&#xff01; 今日思想&#xff1a;不服输的少年啊…...

dify本地源码win10部署

我的win10版本还比较老&#xff0c;winR&#xff0c;输入winver 只要高于我这个版本的都没啥大问题吧&#xff0c;我的安装docker Desktop&#xff0c;搞死人了&#xff0c; 就是win10的Win10 22H2 64之前的版本 win10低版本安装&#xff0c;里面包含wdl2安装程序 https://…...

Spring Cloud Config - 动态配置管理与高可用治理

引言&#xff1a;为什么需要配置中心&#xff1f; 在微服务架构中&#xff0c;配置管理面临分散化、多环境、动态更新三大挑战。传统基于application.yml等配置文件的硬编码方式&#xff0c;导致以下问题&#xff1a; • 环境差异&#xff1a;开发、测试、生产环境配置混杂&a…...

大模型最新面试题系列:微调篇之微调框架(一)

一. 在DeepSpeed中配置零冗余优化&#xff08;ZeRO&#xff09;实现显存优化的步骤 核心原理 ZeRO通过分片&#xff08;Sharding&#xff09;技术将模型参数、梯度和优化器状态分布到多卡&#xff0c;消除冗余存储。三个阶段逐步减少显存占用&#xff1a; Stage 1&#xff1…...

windows第十三章 GDI绘图技术

文章目录 GDI绘图函数介绍设备上下文函数m_hDC GDI对象画笔画刷位图字体区域 案例分享 GDI绘图函数介绍 绘图函数在CDC类里 设备上下文 DC:device context 设备上下文&#xff0c;显卡驱动程序&#xff0c;控制硬件&#xff0c;每个厂商的都不同&#xff0c;操作系统层面&am…...

使用 Nginx 进行前端灰度发布的策略与实践

1. 引言 灰度发布的概念 灰度发布&#xff0c;也称为金丝雀发布&#xff0c;是一种软件发布策略&#xff0c;通过向一小部分用户群体逐步推出新版本&#xff0c;收集反馈并监控性能&#xff0c;以确保新版本在大规模部署前不会出现问题。这种方法可以有效降低发布风险&#x…...

有了大语言模型还需要 RAG 做什么

一、百炼平台简介 阿里云的百炼平台就像是一个超级智能的大厨房&#xff0c;专门为那些想要做出美味AI大餐的企业和个人厨师准备的。你不需要从头开始做每一道菜&#xff0c;因为这个厨房已经为你准备了很多预制食材&#xff08;预训练模型&#xff09;&#xff0c;你可以根据…...

pytest快速入门 - 目录:半天掌握pytest

1 pytest快速入门 - 目录 本系列文章将快速的带领用户进入pytest领域&#xff0c;通过阅读本专栏&#xff0c;用户将可以熟练掌握pytest的基本用法&#xff0c;同时对测试前置条件的构造、后置条件的清理等有较深入的了解&#xff0c;特别是后置条件的执行完备度有一个认识。 …...

2.4 python网络编程

在当今数字化的时代&#xff0c;网络连接着世界的每一个角落。从简单的网页浏览到复杂的分布式系统&#xff0c;网络编程无处不在。Python 作为一种功能强大且易于学习的编程语言&#xff0c;在网络编程领域占据着重要的地位。它丰富的库和简洁的语法使得开发者能够高效地构建各…...

网络变压器的主要电性参数与测试方法(4)

Hqst盈盛&#xff08;华强盛&#xff09;电子导读&#xff1a;网络变压器的主要电性参数与测试方法&#xff08;4&#xff09;.. 今天我们继续来看看网络变压器的2个重要电性参数与它的测试方法&#xff1a; 1.反射损耗&#xff08;Return loss&…...

【Springboot知识】开发属于自己的中间件健康监测HealthIndicate

文章目录 **一、技术栈****二、项目结构****三、依赖配置 (pom.xml)****四、配置文件 (application.yml)****五、自定义健康检查实现****1. Redis健康检查****2. Elasticsearch健康检查****3. Kafka健康检查****4. MySQL健康检查** **六、自定义健康检查接口 (可选)****七、测试…...

蓝桥杯备赛-二分-技能升级

问题描述 小蓝最近正在玩一款 RPG 游戏。他的角色一共有 NN 个可以加攻击力的技能。 其中第 ii 个技能首次升级可以提升 AiAi​ 点攻击力, 以后每次升级增加的点数 都会减少 Bi。「AiBi⌉Bi​。「Bi​Ai​​⌉ (上取整) 次之后, 再升级该技能将不会改变攻击力。 现在小蓝可以…...

【GPT入门】第18课 langchain介绍与API初步体验

【GPT入门】langchain第一课 langchain介绍与API初步体验 1. langchain介绍定义特点1. 模块化与灵活性2. 链式调用机制3. 数据连接能力4. 记忆管理功能5. 提示工程支持6. 可扩展性 2.langchain核心组件架构图3. 最简单的helloworld入门 1. langchain介绍 LangChain 是一个用于…...

Django部署Filemanagement

Pycharm搭建项目安装虚拟环境 mysqlclient对mysql的安装&#xff0c;配置有要求 pymsql伪装成mysqlclient&#xff0c;pymysql可以操纵mysql pip install pymysql操作sql5.7 mysql8.0会出现与pycharm不兼容问题&#xff0c;会报错&#xff0c;所以降到5.7 # 进入mysql 需要…...

Python的types库学习记录

types 库是 Python 标准库中的一部分&#xff0c;它提供了与 Python 对象类型相关的工具和常量&#xff0c;有助于在运行时处理和操作不同类型的对象。 以下是对 types 库的详细介绍&#xff1a; 主要用途 • 类型检查&#xff1a;在运行时判断对象的类型。 • 动态创建和操作…...

C# 表达式树详解

总目录 前言 在 C# 中&#xff0c;表达式树&#xff08;Expression Trees&#xff09;是一种强大的特性&#xff0c;允许开发者将代码表示为数据结构。这使得我们可以在运行时动态地创建和操作代码逻辑&#xff0c;广泛应用于 LINQ 查询、动态方法生成以及反射等领域。本文将深…...

分别用树型和UML结构展示java集合框架常见接口和类

树型结构展示java集合框架常见接口和类 Java 集合框架中的接口和子类关系可以用树形结构来展示。以下是一个简化的树形结构&#xff0c;展示了主要的接口和一些重要的实现类&#xff1a; java.util.Collection ├── java.util.List │ ├── java.util.ArrayList │ ├…...

蓝桥杯备赛-二分-青蛙过河

问题描述 小青蛙住在一条河边, 它想到河对岸的学校去学习。小青蛙打算经过河里 的石头跳到对岸。 河里的石头排成了一条直线, 小青蛙每次跳跃必须落在一块石头或者岸上。 不过, 每块石头有一个高度, 每次小青蛙从一块石头起跳, 这块石头的高度就 会下降 1 , 当石头的高度下降…...

uniapp+微信小程序+最简单局部下拉刷新实现

直接上代码 <scroll-view style"height: 27vh;" :scroll-top"scrollTop" scroll-y"true"scrolltolower"onScrollToLower1" lower-threshold"50"refresher-enabled"true" refresherrefresh"onRefresherR…...

Spring Boot 3.x 中 @NotNull 与 @NonNull 的深度解析

在 Java 开发领域&#xff0c;尤其是在 Spring Boot 生态系统中&#xff0c;空指针异常&#xff08;NPEs&#xff09;始终是一个顽固的挑战。这些运行时错误可能导致应用程序崩溃、数据不一致以及糟糕的用户体验。为了应对这一问题&#xff0c;Java 社区开发了各种空安全机制&a…...

SQLark 实战 | 如何从Excel、csv、txt等外部文件进行数据导入

数据导入导出是应用开发者在平时开发中最常用的操作之一&#xff0c;SQLark 里提供了方便的图形化界面来完成导入导出。本文先和大家分享如何从 Excel、csv、txt 等外部文件导入数据到数据库表中。 &#x1f449; 前往 SQLark 官网&#xff1a;www.sqlark.com 下载全功能免费版…...

MATLAB中envelope函数使用

目录 说明 示例 chirp 的解析包络 使用滤波器计算多通道信号的解析包络 录音信号的移动 RMS 包络 语音信号的峰值包络 不对称序列的包络 envelope函数的功能是提取信号的包络。 语法 [yupper,ylower] envelope(x) [yupper,ylower] envelope(x,fl,analytic) [yupper,…...

ES搭建详细指南+常见错误解决方法

Elasticsearch&#xff08;ES&#xff09;是一款开源的、分布式的、RESTful风格的搜索和数据分析引擎。它用于全文搜索、结构化搜索、分析等场景。以下是Elasticsearch的搭建步骤以及处理常见错误的方法。 Elasticsearch搭建步骤&#xff1a; 1.环境准备&#xff1a; 确保你的…...

Unity 封装一个依赖于MonoBehaviour的计时器(上) 基本功能

灵感来自下面这本书的协程部分,因此我就自己尝试写了一个 我的新书Unity3D游戏开发&#xff08;第3版&#xff09; | 雨松MOMO程序研究院 如果你不知道什么是协程:unity保姆级教程之协同程序_unity协同-CSDN博客 一句话概括:协程就是单线程的异步操作,其作用于Unity的主线程 1…...

PostgreSQL数据库版本支持策略

PostgreSQL数据库版本支持策略 主要版本会进行复杂的更改&#xff0c;因此无法以向后兼容的方式维护数据目录的内容。重大升级需要转储/重新加载数据库或使用pg_upgrade应用程序。我们还建议您阅读您计划升级到的主要版本的升级部分。您可以从一个主要版本升级到另一个&#xf…...

应用层之网络应用模型,HTTP/HTTPS协议

应用层是网络协议栈的最顶层&#xff0c;直接为应用程序提供通信服务&#xff0c;定义了不同主机间应用进程交互的规则&#xff0c;包括报文类型、语法、语义及通信时序 一、网络应用模型 1.定义及特点 模型定义核心特点典型应用场景C/S客户端向服务器发起请求&#xff0c;服…...

(七)Spring Boot学习——Redis使用

有部分内容是常用的&#xff0c;为了避免每次都查询数据库&#xff0c;将部分数据存入Redis。 一、 下载并安装 Redis Windows 版的 Redis 官方已不再维护&#xff0c;你可以使用 微软提供的 Redis for Windows 版本 或者 使用 WSL&#xff08;Windows Subsystem for Linux&a…...

11 | 给 Gin 服务器添加中间件

提示&#xff1a; 所有体系课见专栏&#xff1a;Go 项目开发极速入门实战课&#xff1b;欢迎加入 云原生 AI 实战 星球&#xff0c;12 高质量体系课、20 高质量实战项目助你在 AI 时代建立技术竞争力&#xff08;聚焦于 Go、云原生、AI Infra&#xff09;&#xff1b;本节课最终…...

selenium等待

通常代码执行的速度⽐页⾯渲染的速度要快,如果避免因为渲染过慢出现的⾃动化误报的问题呢?可以使⽤selenium中提供的三种等待⽅法: 1. 隐式等待(Implicit Wait) 隐式等待适用于全局,它告诉 WebDriver 在查找元素时等待一定的时间,直到元素出现。 如果超时,WebDriver 不…...

为什么List、Set集合无法在遍历的时候修改内部元素

以常用集合ArrayList为例&#xff0c;ArrayList 在遍历过程中无法直接修改内部元素的结构&#xff08;例如通过 remove() 或 add() 方法修改元素&#xff09;&#xff0c;是因为 遍历的过程中修改结构 可能会导致 不一致的行为、并发修改异常 或 逻辑错误。 注意&#xff1a;和…...

使用 Elasticsearch 构建多模式 RAG 系统:哥谭市的故事

作者&#xff1a;来自 Elastic Alex Salgado 学习如何构建一个多模态检索增强生成 (RAG) 系统&#xff0c;该系统集成文本、音频、视频和图像数据&#xff0c;以提供更丰富的、具有上下文的信息检索。 在这篇博客中&#xff0c;你将学习如何使用 Elasticsearch 构建一个多模态 …...

单一责任原则在Java设计模式中的深度解析

在软件开发中&#xff0c;设计模式提供了一种解决特定问题的思路。在众多的设计原则中&#xff0c;单一责任原则&#xff08;Single Responsibility Principle&#xff0c;SRP&#xff09;是一个非常重要的概念。它主要强调一个类应该只有一个责任&#xff0c;也就是说&#xf…...

设计模式学习记录

设计模式23种 创建型抽象工厂模式工厂模式生成器模式原型模式单例模式 结构型适配器模式桥接模式组合模式装饰模式外观模式享元模式代理模式 行为型责任链模式命令模式解释器模式迭代器模式中介者模式备忘录模式观察者模式状态模式策略模式模版方法模式访问者模式 创建型 与对…...

set_clock_groups

一、命令参数与工具处理逻辑 核心参数定义 参数定义工具行为工具兼容性-asynchronous完全异步时钟组&#xff0c;无任何相位或频率关系&#xff08;如独立晶振、不同时钟树&#xff09;工具完全禁用组间路径的时序分析&#xff0c;但需用户自行处理跨时钟域&#xff08;CDC&a…...

QT创建项目(项目模板、构建系统、选择类、构建套件)

1. 项目模版 项目类型界面技术适用场景核心依赖模块开发语言Qt Widget ApplicationC Widgets传统桌面应用&#xff08;复杂控件&#xff09;Qt WidgetsCQt Console Application无 GUI命令行工具、服务Qt CoreCQt Quick ApplicationQML/Quick现代跨平台应用&#xff08;动画/触…...

麒麟系统利用pycharm生成deb文件

在麒麟系统&#xff08;Kylin OS&#xff09;上使用 PyCharm 进行 Python 开发并生成 .deb 可安装软件包&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 准备工作 安装 PyCharm&#xff1a;确保已经在麒麟系统上安装了 PyCharm&#xff0c;可以使用官方提供的安装包进…...

超声重建,3D重建 超声三维重建,三维可视化平台 UR 3D Reconstruction

1. 超声波3D重建技术的实现方法与算法 技术概述 3D超声重建是一种基于2D超声图像生成3D体积数据的技术&#xff0c;广泛应用于医学影像领域。通过重建和可视化三维结构&#xff0c;3D超声能够显著提高诊断精度和效率&#xff0c;同时减少医生的脑力负担。本技术文档将详细阐述…...

Qt 信号与槽

目录 Qt信号和槽 connect函数 connect使用方法 自定义信号 与 自定义槽 Qt界面化工具自动生成的槽 自定义信号 带参数的信号和槽 信号与槽的断开 Qt信号和槽 谈到信号&#xff0c;设计3个要素 信号源&#xff1a;谁发出了信号 信号触发条件&#xff1a;哪个控件的哪个…...

卷积神经网络 - 卷积的变种、数学性质

本文我们来学习卷积的变种和相关的数学性质&#xff0c;为后面学习卷积神经网络做准备&#xff0c;有些概念可能不好理解&#xff0c;可以先了解其概念&#xff0c;然后慢慢理解、逐步深入。 在卷积的标准定义基础上&#xff0c;还可以引入卷积核的滑动步长和零填充来增加卷积…...

ubuntu 和 RV1126 交叉编译Mosqutiio-1.6.9

最近需要交叉编译mosquitto&#xff0c;遇到一些小问题记录一下。 1.众所周知使用它自带的Makefile编译的时候&#xff0c;只需要在编译前&#xff0c;指定它config.mk中的变量&#xff1a;CFLAGS头文件路径 和 LDFLAGS库文件路径就ok&#xff0c;例子如下&#xff1a; expor…...