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

系统架构设计师 10:软件架构的演化和维护

一、软件架构演化

如果软件架构的定义是 SA={components, connectors, constraints},也就是说,软件架构包括组件、连接件和约束三大要素,这类软件架构演化主要关注的就是组件、连接件和约束的添加、修改与删除等。

二、面向对象软件架构演化过程

演化类型

说明

对象演化

对象本身包含了众多的属性,如接口、类型、语义等,这些属性的演化对于对象之间的交互过程并无影响。因此,会对架构设计的动态行为产生影响的演化只包括AddObject和DeleteObject两种。

消息演化

消息演化是面向对象软件架构演化的核心。

我们将消息演化分为AddMessage、DeleteMessage、SwapMessageOrder(交换消息的时间顺序)、OverturnMessage(反转消息的发送对象与接收对象)、ChangeMessageModule(改变消息的发送或接收对象)五种。

复合片段演化

复合片段是对象交互关系的控制流描述,表示可能发生在不同场合的交互,与消息同属于连接件范畴。

复合片段的演化分为AddFragment、DeleteFragment、FragmentTypeChange(改变复合片段的类型)、FragmentConditionChange(改变复合片段内部执行的条件)。

约束演化

约束演化即直接对约束信息进行添加(AddConstraint)或删除(DeleteConstraint)。

三、软件架构演化方式

1 软件架构演化时期

1. 设计时演化:发生在体系结构模型和与之相关的代码编译之前的软件架构演化。

2. 运行前演化:发生在执行之前、编译之后的软件架构演化。

3. 有限制运行时演化:在某些特定约束满足时,进行的一些规定好的演化操作。

4. 运行时演化:系统的体系结构在运行时不能满足要求时发生的软件架构演化,此时的演化是最难实现的。

2 软件架构静态演化

一次完整软件架构演化过程可以看作经过一系列原子演化操作组合而成。

1. 与可维护性相关的架构演化操作。

名称

说明

AMD(Add Module Dependence)

增加模块间的依赖关系

RMD(Remove Module Dependence)

删除模块间的依赖关系

AMI(Add Module Interface)

增加模块间的接口

RMI(Remove Module Interface)

删除模块间的接口

AM(Add Module)

增加一个模块

RM(Remove Module)

删除一个模块

SM(Split Module)

拆分模块

AGM(Aggregate Modules)

聚合模块

2. 与可靠性相关的架构演化操作。

    架构演化的可靠性评估基于UML用例图、部署图和顺序图。

名称

说明

AMS(Add Message)

在顺序图中增加模块交互消息

RMS(Remove Message)

在顺序图中删除模块交互消息

AO(Add Object)

在顺序图中增加交互对象

RO(Remove Object)

在顺序图中删除交互对象

AF(Add Fragment)

在顺序图中增加消息片段

RF(Remove Fragment)

在顺序图中删除消息片段

CF(Change Fragment)

在顺序图中修改消息片段

AU(Add Use Case)

在用例图中为参与者增加一个可执行用例

RU(Remove Use Case)

在用例图中为参与者删除某个可执行用例

AA(Add Actor)

在用例图中增加参与者

RA(Remove Actor)

在用例图中删除参与者

3 静态演化实例:正交软件架构

对于复杂的应用系统,通过对功能进行分层和线索化,可以形成正交软件结构(Orthogonal Software Architecture)。

正交体系结构中同一层级中的软件不允许相互调用,故每个变动仅影响一条线索。

4 软件架构动态演化

目前,实现软件架构动态演化的技术主要有两种:

1. 采用动态软件架构(DSA)。

    动态软件架构是指在系统执行期间可以修改自身的架构。

    应用实例:PKUAS。

2. 进行动态重配置(DR)。

    动态重配置是指在软件部署之后对配置信息进行修改。

    应用实例:可重用、可配置的产品线架构。

4.1 DSA描述语言

DSA实施动态演化需要DSA描述语言的支持,按照描述视角可将这些语言分为三类:

1. 基于行为视角的π-ADL。

    使用进程代数来描述具有动态性的行为。

    进程代数将以序列化方式执行的一系列行为抽象为进程,行为的交互被简化为进程的合成。

2. 基于反射视角的Pilar。

    利用反射理论显式地为元信息建立模型。

3. 基于协调视角的LIME。

    注重计算和协调部分的分离,利用协调论的原理来解决动态性交互。

四、软件架构演化原则

1. 演化成本控制(Evolution Cost Control,ECC)原则。

    演化成本要控制在预期的范围之内,也就是演化成本要明显小于重新开发成本。

2. 进度可控(Schedule Control)原则。

    架构演化要在预期时间内完成,也就是时间成本可控。

3. 风险可控(Risk Control)原则。

    架构演化过程中的经济风险、时间风险、人力风险、技术风险和环境风险等必须在可控范围内。

4. 主体维持原则。

    对称稳定增长(the Average Incremental Growth,AIG)原则所有其他因素必须与软件演化协调,开发人员、销售人员、用户必须熟悉软件演化的内容,从而达到令人满意的演化。因此,软件演化的平均增量的增长须保持平稳,保证软件系统主体行为稳定。

5. 系统总体结构优化(Optimization of Whole Structure)原则。

    架构演化要遵循系统总体结构优化原则,使得演化之后的软件系统整体结构(布局)更加合理。

6. 平滑演化(Invariant Work Rate,IWR)原则。

    在软件系统的生命周期里,软件的演化速率趋于稳定,如相邻版本的更新率相对固定。

7. 目标一致(Objective Conformance)原则。

    架构演化的阶段目标和最终目标要一致。

8. 模块独立演化原则。

    软件中各模块(相同制品的模块,如Java的某个类或包)自身的演化最好相互独立,或者至少保证对其他模块的影响比较小或影响范围比较小。

9. 影响可控(Impact Limitation)原则。

    软件中一个模块如果发生变更,其给其他模块带来的影响要在可控范围内,也就是影响范围可预测。

10. 复杂性可控(Complexity Controllability)原则。

    架构演化必须要控制架构的复杂性,从而进一步保障软件的复杂性在可控范围内。

11. 有利于重构(Useful for Refactoring)原则。

    架构演化要遵循有利于重构原则,使得演化之后的软件架构更便于重构。

12. 有利于重用(Useful for Reuse)原则。

    架构演化最好能维持,甚至提高整体架构的可重用性。

13. 设计原则遵从性(Design Principles Conformance)原则。

    架构演化最好不能与架构设计原则冲突。

14. 适应新技术(Technology Independence,TI)原则。

    软件要独立于特定的技术手段,这样才能够让软件运行于不同平台。

15. 环境适应性(Platform Adaptability)原则。

    架构演化后的软件版本能够比较容易适应新的硬件环境与软件环境。

16. 标准依从性(Standard Conformance)原则。

    架构演化不会违背相关质量标准(国际标准、国家标准、行业标准、企业标准等)。

17. 质量向好(Quality Improvement,QI)原则。

    通过演化使得所关注的某个质量指标或某些质量指标的综合效果变得更好或者更满意,例如可靠性提高了。

18. 适应新需求(New Requirement Adaptability)原则。

    架构演化要很容易适应新的需求变更;架构演化不能降低原有架构适应新需求的能力;架构演化最好可以提高适应新需求的能力。

五、软件架构演化评估方法

量化分析,有需要再阅读。

六、大型网站系统架构演化实例

大型网站的技术挑战主要来自于庞大的用户,高并发的访问和海量的数据,任何简单的需求一旦需要处理数以P计的数据和面对数以亿计的用户,问题就会变得棘手。通常大型网站架构主要解决这类问题。

1 第一阶段:单体架构

小型网站最开始没有太多人访问,只需要一台服务器就绰绰有余,应用程序、数据库、文件等所有资源都在这台服务器上。

2 第二阶段:垂直架构

随着网站业务的发展,一台服务器逐渐不能满足需求,越来越多的用户访问导致性能越来越差,越来越多的数据导致存储空间不足,这时就需要将应用和数据分离。

应用和数据分离后整个网站使用3台服务器:应用服务器、文件服务器和数据库服务器。

这3台服务器对硬件资源的要求各不相同:

1. 应用服务器需要处理大量的业务逻辑,因此需要更快更强大的处理器速度。

2. 数据库服务器需要快速磁盘检索和数据缓存,因此需要更快的磁盘和更大的内存。

3. 文件服务器需要存储大量用户上传的文件,因此需要更大容量的硬盘。

3 第三阶段:使用缓存改善网站性能

随着用户逐渐增多,网站又一次面临挑战:数据库压力太大导致访问延迟,进而影响整个网站的性能,用户体验受到影响。这时可以使用缓存来进一步优化。

网站使用的缓存可以分为两种:

1. 缓存在应用服务器上的本地缓存。

    本地缓存的访问速度更快一些,但是受应用服务器内存限制,其缓存数据量有限,而且会出现和应用程序争用内存的情况。

2. 缓存在专门的分布式缓存服务器上的远程缓存。

    远程分布式缓存可以使用集群的方式,部署大内存的服务器作为专门的缓存服务器,可以在理论上做到不受内存容量限制的缓存服务。

4 第四阶段:使用服务集群改善网站并发处理能力

使用缓存后,数据访问压力得到有效缓解,但是单一应用服务器能够处理的请求连接有限,在网站访问高峰期,应用服务器成为整个网站的瓶颈。

使用集群是网站解决高并发、海量数据问题的常用手段。

通过负载均衡调度服务器,可以将来自用户浏览器的访问请求分发到应用服务器的任何一台服务器上,如果有更多用户,就在集群中加入更多的应用服务器,使应用服务器的压力不再成为整个网站的瓶颈。

5 第五阶段:数据库读写分离

网站在使用缓存后,使对大部分数据读操作访问都可以不通过数据库就能完成,但是仍有一部分读操作(缓存访问不命中、缓存过期)和全部的写操作都需要访问数据库,在网站的用户达到一定规模后,数据库因为负载压力过高而成为网站的瓶颈。目前大部分的主流数据库都提供主从热备功能,通过配置两台数据库主从关系,可以将一台数据库服务器的数据更新同步到另一台服务器上。网站利用数据库的这一功能,实现数据库读写分离,从而改善数据库负载压力。

应用服务器在写数据的时候,访问主数据库,主数据库通过主从复制机制将数据更新同步到从数据库,这样当应用服务器读数据的时候,就可以通过从数据库获得数据。为了便于应用程序访问读写分离后的数据库,通常在应用服务器端使用专门的数据访问模块,使数据库读写分离对应用透明。

6 第六阶段:使用反向代理和CDN加速网站响应

随着网站业务不断发展,用户规模越来越大,由于区域的差别使得网络环境异常复杂,不同地区的用户访问网站时,速度差别也极大。有研究表明,网站访问延迟和用户流失率正相关,网站访问越慢,用户越容易失去耐心而离开。为了提供更好的用户体验,留住用户,网站需要加速网站访问速度。主要手段有使用CDN和反向代理。CDN和反向代理的基本原理都是缓存。

CDN部署在网络提供商的机房,使用户在请求网站服务时,可以从距离自己最近的网络提供商机房获取数据。

反向代理则部署在网站的中心机房,当用户请求到达中心机房后,首先访问的服务器是反向代理服务器,如果反向代理服务器中缓存着用户请求的资源,就将其直接返回给用户。

使用CDN和反向代理的目的都是今早返回数据给用户,一方面加快用户访问速度,另一方面也减轻后端服务器的压力。

7 第七阶段:使用分布式文件系统和分布式数据库系统

数据库经过读写分离后,从一台服务器拆分成两台服务器,但是随着网站业务的发展依然不能满足需求,这时需要使用分布式数据库。分布式数据库是网站数据拆分的最后手段,只有在单表数据规模非常庞大的时候才使用。不到不得已时,网站更常用的数据库拆分手段是业务分库,将不同业务的数据部署在不同的物理服务器上。

文件系统也一样,必要时可以使用分布式文件系统。

8 第八阶段:使用NoSQL和搜索引擎

随着网站业务越来越复杂,对数据存储和检索的需求也越来越复杂,网站需要采用一些非关系数据库技术如NoSQL和非数据库查询技术如搜索引擎。NoSQL和搜索引擎都是源自互联网的技术手段,对可伸缩的分布式特性具有更好的支持。应用服务器则通过一个统一数据访问模块访问各种数据,减轻应用程序管理诸多数据源的麻烦。

9 第九阶段:业务拆分

大型网站为了应对日益复杂的业务场景,通过使用分而治之的手段将整个网站业务分成不同的产品线。如大型购物交易网站都会将首页、商铺、订单、买家、卖家等拆分成不同的产品线,分归不同的业务团队负责。

具体到技术上,也会根据产品线划分,将一个网站拆分成许多不同的应用,每个应用独立部署。应用之间可以通过一个超链接建立关系(在首页上的导航链接每个都指向不同的应用地址),也可以通过消息队列进行数据分发,当然最多的还是通过访问同一个数据存储系统来构成一个关联的完整系统。

10 第十阶段:分布式服务

随着业务拆分越来越小,存储系统越来越庞大,应用系统的整体复杂度呈指数级增加,部署维护越来越困难。由于所有应用要和所有数据库系统连接,在数万台服务器规模的网站中,这些连接的数目是服务器规模的平方,导致数据库连接资源不足,拒绝服务。

既然每一个应用系统都需要执行许多相同的业务操作,比如用户管理、商品管理等,那么可以将这些共用的业务提取出来,独立部署。由这些可复用的业务连接数据库,提供共用业务服务,而应用系统只需要管理用户界面,通过分布式服务调用共用业务服务完成具体业务操作。

大型网站的架构演化到这里,基本上大多数的技术问题都得以解决,诸如跨数据中心的实时数据同步和具体网站业务相关的问题也都可以通过组合改进现有技术架构解决。

七、软件架构维护

1 软件架构知识管理

软件架构知识管理是对架构设计中所隐含的决策来源进行文档化表示,进而在架构维护过程中帮助维护人员对架构的修改进行完善的考虑,并能够为其他软件架构的相关活动提供参考。

架构知识 = 架构设计 + 架构设计决策,即需要说明在进行架构设计时采用此种架构的原因。

2 软件架构可维护性度量指标

1. 圈复杂度(CCN)。

2. 扇入扇出度(FFC)。

    扇入是指直接调用该模块的上级模块的个数,扇出指该模块直接调用的下级模块的个数。

3. 模块间耦合度(CBO)。

    模块与其他模块交互的频繁程度。一般来说,组件与其他组件的依赖关系及接口越多,该组件的耦合度越大。

4. 模块的响应(RFC)。

    组件执行所需的功能的数量,包括接口提供的功能、依赖的其他模块提供的功能以及子模块提供的功能。

5. 模块间内聚度TCC和LCC。

相关文章:

系统架构设计师 10:软件架构的演化和维护

一、软件架构演化 如果软件架构的定义是 SA{components, connectors, constraints},也就是说,软件架构包括组件、连接件和约束三大要素,这类软件架构演化主要关注的就是组件、连接件和约束的添加、修改与删除等。 二、面向对象软件架构演化…...

Windows 11 绕过 TPM 方法总结,通用免 TPM 镜像下载 (2023 年 7 月更新)

Windows 11 绕过 TPM 方法总结,通用免 TPM 镜像下载 (2023 年 7 月更新) 在虚拟机、Mac 电脑和 TPM 不符合要求的旧电脑上安装 Windows 11 的通用方法总结 请访问原文链接:https://sysin.org/blog/windows-11-no-tpm/,查看最新版。原创作品…...

EXCEL,如何比较2个表里的数据差异(使用数据透视表)

目录 1 问题: 需要比较如下2个表的内容差异 1.1 原始数据喝问题 1.2 提前总结 2 使用EXCEL公式方法 2.1 新增辅助列: 辅助index 2.2 具体公式 配合条件格式 使用 3 数据透视表方法 3.1 新增辅助列: 辅助index 3.2 需要先打开 数据透视表向导 …...

字节抖音小程序,使用 uniapp 调起内置支付

字节抖音小程序,使用 uniapp 调起内置支付 第一步:提交订单 后端通过抖音预下单接口,提交支付订单信息。 预下单接口_小程序_抖音开放平台预下单接口 提交支付订单信息。 ## 使用限制 无 ## 接口说明 预下单接口需要保证同一app_id下每笔订…...

django模板继承和组件了解

1、模板继承 什么时候需要用到模板呢,比如我们在开发的页面的导航栏,你点不同的功能页面这个导航栏都是一样的,如果每个页面都要加上这个导航条会写重复代码,而且如果导航条有变化,每个页面都要修改,这个是…...

首屏优化,给以图片为背景的元素增加相似背景,优化用户体验,background-image 绘制规则

每日鸡汤:每个你想要学习的瞬间都是未来的你向自己求救 假设你的项目首页有个大大的图片作为背景,那么这个图片肯定会在网络不好的时候加载出来很慢,导致用户回看到一大片白屏,这样很影响体验。这也是老生常谈的首屏优化的问题。例…...

【用户体验分析报告】 按需加载组件,导致组件渲染卡顿,影响交互体验?组件拆包预加载方案来了!

首先,我们看一些针对《如何提升应用首屏加载体验》的文章,提到的必不可少的措施,便是减少首屏幕加载资源的大小,而减少资源大小必然会想到按需加载措施。本文提到的便是一个基于webpack 插件与 react 组件实现的一套研发高度自定义…...

idea 关闭页面右侧预览框/预览条

idea 关闭页面右侧预览框 如图,预览框存在想去除 找了好多方法,什么去掉“setting->appearance里的show editor preview tooltips”的对钩;又或者在该预览区的滚动条上右键,“取消勾选show code lens on scrollbar hover”。都…...

CSS3 Flexbox

Flex 是 Flexible Box 的缩写,意为弹性盒子布局。 CSS3中一种新的布局模式:W3C在2009年提出的一种布局方案,一种当页面需要适应不同的屏幕大小以及设备类型时确保元素拥有恰当的行为的布局方式。其目的是提供一种更加有效的方式来对一个容器…...

东南大学轴承故障诊断(Python代码,CNN模型,适合复合故障诊断研究)

运行代码要求: 代码运行环境要求:Keras版本>2.4.0,python版本>3.6.0 本次实验主要是在两种不同工况数据下,进行带有复合故障的诊断实验,没有复合故障的诊断实验。 实验结果证明,针对具有复合故障的…...

ubuntu--Motrix

Motrix官网 https://motrix.app/ 适用于windows和ubuntu 资源链接 链接: https://pan.baidu.com/s/16ka-w30BXJn066absXJXCA 密码: cds2 下载上面的资源,打开终端,安装Motrix sudo dpkg -i XXX.deb 在ubuntu安装好chrome,然后打开设置中…...

PHP 3des加解密新旧方法可对接加密

一、旧3des加解密方法 <?php class Encrypt_3DES {//加密秘钥&#xff0c;private $_key;private $_iv;public function __construct($key, $iv){$this->_key $key;$this->_iv $iv;}/*** 对字符串进行3DES加密* param string 要加密的字符串* return mixed 加密成…...

【朴素贝叶斯-新闻主题分类】

朴素贝叶斯对新闻进行分类 朴素贝叶斯算法是一种常用的文本分类方法&#xff0c;特别适用于自然语言处理任务&#xff0c;如新闻分类。在这篇博客中&#xff0c;我们将使用Python的scikit-learn库来实现朴素贝叶斯算法&#xff0c;并将其应用于新闻分类任务。 数据准备 首先…...

安卓面试问题记录

目录 1. JNI和NDK1.谈谈你对JNI和NDK的理解2.简要的JNI调用过程:2. 线程、同步、异步1.Java创建线程的方式有几种?start()方法和 run()方法的区别2.Handler 机制和原理3.为什么在子线程中创建Handler会抛异常?4.Android中的ANR的解决方法5.intentservice有什么优点?6.okhtt…...

php-golang-jsonrpc2.0 rpc-codec/jsonrpc2和tivoka/tivoka实践

golang代码&#xff1a; package main import ( "context" "net" "net/rpc" "github.com/powerman/rpc-codec/jsonrpc2" ) type App struct{} type Res struct { Code int json:"code" Msg string json:"msg&quo…...

听力词汇笔记(6级)

2022年9月六级 1.personality traits:人格特征 2.all of this notwithstanding:尽管如此 3.come under&#xff1a;受到 4.scrutiny&#xff1a;关注 5.highly responsive to:对....高度敏感 6.preteen year:青春期前 7.susceptible to:受....影响 8.take sharp preced…...

【JVM】详细解析java创建对象的具体流程

目录 一、java创建对象的几种方式 1.1、使用new关键字 1.2、反射创建对象 1.2.1、Class.newInstance创建对象 1.2.2、调用构造器再去创建对象Constructor.newInstance 1.3、clone实现 1.4、反序列化 二、创建对象的过程 2.1、分配空间的方式 1、指针碰撞 2、空闲列表 …...

kafka怎么用代码读取数据

Kafka可以通过Java语言中的Kafka客户端库来读取数据。以下是一个简单的Java代码示例&#xff0c;通过Kafka Consumer API从Kafka集群中读取数据&#xff1a; java import java.util.Properties; import org.apache.kafka.clients.consumer.ConsumerRecords; import org.apache.…...

网关与路由器的区别

仅需2分钟&#xff0c;彻底明白网关的工作原理_哔哩哔哩_bilibili网关_百度百科 一、网关的概念 网关(Gateway)又称网间连接器、协议转换器。网关在网络层以上实现网络互连&#xff0c;是复杂的网络互连设备&#xff0c;仅用于两个高层协议不同的网络互连。网关既可以用于广域…...

助力工业物联网,工业大数据之工单事实指标需求分析【二十】

文章目录 1&#xff1a;工单事实指标需求分析2&#xff1a;工单事实指标构建 1&#xff1a;工单事实指标需求分析 目标&#xff1a;掌握DWB层工单事实指标表的需求分析 路径 step1&#xff1a;目标需求step2&#xff1a;数据来源 实施 目标需求&#xff1a;基于工单信息统计等…...

python_PyQt5开发工具结构基础

写在前面&#xff1a; 考虑已经陆陆续续在平台写了几篇PyQt5开发的小工具&#xff0c;后续还会继续发布新的新工具&#xff0c;这些工具都基于一个基础结构往上构建&#xff0c;这个基础结构是本人自己开发的习惯&#xff0c;在这里把工具的基础结构代码抽取出来&#xff0c;后…...

【C++】入门基础2

引用 概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空 间&#xff0c;它和它引用的变量共用同一块内存空间 类型& 引用变量名(对象名) 引用实体&#xff1b; 注意&#xff1a;引用类型必须和引用实体是…...

Reinforcement Learning with Code 【Chapter 8. Value Funtion Approximation】

Reinforcement Learning with Code This note records how the author begin to learn RL. Both theoretical understanding and code practice are presented. Many material are referenced such as ZhaoShiyu’s Mathematical Foundation of Reinforcement Learning, . 文章…...

常用InnoDB参数介绍

常用InnoDB参数介绍 1 状态参数1.1 InnoDB 缓冲池状态监控1.1.1 Innodb_buffer_pool_pages_total1.1.2 Innodb_buffer_pool_pages_data1.1.3 Innodb_buffer_pool_bytes_data1.1.4 Innodb_buffer_pool_pages_dirty1.1.5 Innodb_buffer_pool_bytes_dirty1.1.6 Innodb_buffer_pool…...

云原生网关部署新范式丨 Higress 发布 1.1 版本,支持脱离 K8s 部署

作者&#xff1a;澄潭 版本特性 Higress 1.1.0 版本已经 Release&#xff0c;K8s 环境下可以使用以下命令将 Higress 升级到最新版本&#xff1a; kubectl apply -f https://github.com/alibaba/higress/releases/download/v1.1.0/customresourcedefinitions.gen.yaml helm …...

【通讯录】--C语言

&#x1f490; &#x1f338; &#x1f337; &#x1f340; &#x1f339; &#x1f33b; &#x1f33a; &#x1f341; &#x1f343; &#x1f342; &#x1f33f; &#x1f344;&#x1f35d; &#x1f35b; &#x1f364; &#x1f4c3;个人主页 &#xff1a;阿然成长日记 …...

通过两种实现方式理解CANoe TC8 demo是如何判断接收的以太网报文里的字段的

假设有一个测试用例,需求是:编写一个测试用例,发送一条icmpv4 echo request报文给DUT,identifier字段设置为10。判断DUT能够回复icmpv4 echo reply报文,且identifier字段值为10。 实现:在canoe的simulation setup界面插入一个test节点,ip地址为:192.168.0.1,mac地址为…...

Mysql- 存储引擎

目录 1.Mysql体系结构 2.存储引擎简介 3.存储引擎特点 InnoDB MyISAM Memory 4.存储引擎选择 1.Mysql体系结构 MySQL整体的逻辑结构可以分为4层&#xff1a; 连接层&#xff1a;进行相关的连接处理、权限控制、安全处理等操作 服务层&#xff1a;服务层负责与客户层进行…...

vite / nuxt3 项目使用define配置/自定义,可以使用process.env.xxx获取的环境变量

每日鸡汤&#xff1a;每个你想要学习的瞬间&#xff0c;都是未来的你向自己求救 首先可以看一下我的这篇文章了解一下关于 process.env 的环境变量。 对于vite项目&#xff0c;在我们初始化项目之后&#xff0c;在浏览器中打印 process.env&#xff0c;只有 NODE_ENV这个变量&…...

在Linux、Ubuntu中跨平台编译ARM(AARCH64)平台的binutils

Binutils 是GNU(https://www.gnu.org/)提供的一组二进制工具的集合。通常,在已经安装了Linux操作系统的个人电脑上,系统就已经自带了这个工具集。但在进行嵌入式开发的时候,可能会用到支持ARM64平台的Binutils,这时就需要用到交叉编译。 此前,在【1】我们已经介绍过Ubun…...