【软件系统架构】单体架构

一、引言

        在软件开发的漫长历程中,架构的选择一直是至关重要的决策。单体架构作为一种经典的架构模式,曾经在许多项目中发挥着不可替代的作用。虽然如今微服务等架构逐渐流行,但理解单体架构对于深入掌握软件架构体系仍然有着重要意义。

二、单体架构定义

        单体架构是一种将所有功能模块(如业务逻辑、数据访问、用户界面等)都打包在一个单一的可执行程序中的软件架构。就像是一个大的容器,里面包含了应用程序的所有部分,各个部分紧密耦合,共享代码库、数据库等资源。

三、单体架构发展历史

        早期的软件系统相对简单,单体架构因其简单直接的构建方式而被广泛采用。在计算机技术发展的初期,硬件资源有限,开发人员更倾向于构建紧凑、一体化的应用。随着业务需求的不断增长,单体架构也在不断扩展,但基本的架构模式在很长一段时间内保持不变。例如,许多传统的企业级应用,如早期的ERP系统,大多采用单体架构构建。

四、单体架构特点

(一)简单性

        开发相对简单,所有功能都在一个项目中,对于小型项目或者团队经验不足的情况下,易于上手。开发人员可以快速搭建起一个功能完整的应用,不需要处理复杂的分布式系统的通信、协调等问题。

(二)易于部署

        整个应用只需要部署一个单元,与分布式系统相比,部署过程更加直接。不需要考虑多个服务之间的部署顺序、依赖关系等复杂情况。

(三)紧耦合

        各个功能模块之间相互依赖,共享代码和数据结构。这种紧耦合的特性使得在修改一个模块时,可能会影响到其他模块的功能,导致系统的可维护性随着项目规模的扩大而降低。

五、单体架构细分类型

(一)分层式单体架构

  • 架构特点
    • 通常按照功能将应用分为表示层、业务逻辑层和数据访问层。表示层负责与用户交互,业务逻辑层处理业务规则,数据访问层与数据库交互。这种分层结构使得代码具有一定的组织性,便于开发人员理解和维护。
    • 各层之间通过接口进行通信,上层依赖下层,下层为上层提供服务。例如,表示层调用业务逻辑层的方法来处理用户请求,业务逻辑层再调用数据访问层的方法来获取或存储数据。
  • 适用场景
    • 适用于业务逻辑相对简单、规模较小的应用。比如一些小型的企业内部管理系统,如员工考勤系统,主要功能集中在数据的录入、查询和简单的统计分析,分层式单体架构可以很好地满足需求。

(二)模块化单体架构

  • 架构特点
    • 将应用划分为多个模块,每个模块负责特定的功能集。模块之间有一定的独立性,但仍然在同一个代码库中。例如,在一个电商应用中,可以将用户管理、商品管理、订单管理等分别作为不同的模块。
    • 模块之间可能存在一定的依赖关系,通过定义良好的接口来进行交互。这种架构在一定程度上提高了代码的可维护性和可扩展性,相比分层式单体架构,模块之间的耦合度更低。
  • 适用场景
    • 对于中等规模、功能相对较多但还不足以拆分微服务的应用比较适合。比如一个具有多种业务功能,如在线教育平台中的课程管理、学生学习记录管理、教师管理等功能的应用,可以采用模块化单体架构。

六、单体架构优缺点

分类具体描述示例说明
优点
开发效率单代码库快速开发,无需处理分布式系统复杂性,适合快速原型开发和简单需求项目。初创公司开发用户管理系统,1 周内完成核心功能并上线验证市场。
资源利用仅需单个运行环境,硬件资源占用低,适合小型项目或资源受限场景。小型企业使用 1 台服务器部署单体 ERP 系统,支撑 50 人同时在线办公。
缺点
可维护性差代码库庞大复杂,模块紧耦合,修改易引发连锁反应。修改订单表字段需同步更新订单处理、库存管理、财务结算等多个模块。
扩展性有限无法针对单一功能扩展,需整体升级,导致资源浪费。电商平台订单量激增时,需整体扩容服务器,而非仅扩展订单处理模块。

(一)优点

开发效率

        在项目初期,由于开发人员可以在一个代码库中快速开发功能,不需要考虑复杂的分布式系统构建,所以开发速度较快。对于一些快速原型开发或者需求明确、功能简单的项目来说,能够快速上线。

资源利用

        单体架构的应用只需要一个运行环境,相比于分布式架构,在资源消耗方面可能更低。例如,不需要为多个服务分别配置独立的服务器资源,在小型项目中可以充分利用有限的硬件资源。

(二)缺点

可维护性差

        随着应用规模的增大,代码库变得庞大复杂。由于各个功能模块之间的紧耦合,一个小的修改可能会在整个应用中产生连锁反应。例如,修改数据库结构可能会影响到多个业务逻辑模块,需要对整个应用进行全面的测试。

扩展性有限

        当需要对应用的某个功能进行大规模扩展时,由于单体架构的限制,很难做到独立扩展。例如,在一个单体架构的电商应用中,如果订单处理模块需要应对大量订单的处理,很难单独对该模块进行水平扩展,往往需要对整个应用进行扩展,这可能会带来不必要的资源浪费。

七、单体架构的案例

        以一个传统的图书馆管理系统为例。这个系统包含了图书信息管理(包括图书的录入、查询、借阅等)、读者信息管理(读者注册、借阅记录查询等)以及系统管理(用户权限管理等)等功能。整个系统采用单体架构构建,所有功能都在一个可执行程序中。开发人员使用分层式单体架构,将表示层、业务逻辑层和数据访问层分开。表示层提供用户界面,业务逻辑层处理诸如借阅规则、还书规则等业务逻辑,数据访问层与数据库交互存储和获取相关信息。

早期的 eBay 网站​

        eBay 在发展初期采用了单体架构。当时,其业务主要集中在提供一个在线拍卖平台,功能相对单一。单体架构使得 eBay 能够快速开发和部署网站,满足用户的基本需求。开发团队可以专注于核心业务功能的实现,如商品发布、竞拍、交易等功能的开发。随着业务的增长,eBay 逐渐面临性能和可扩展性的挑战,才开始逐步向分布式架构转型。​

小型企业的内部管理系统​

        许多小型企业的内部管理系统,如财务管理系统、人力资源管理系统等,常采用单体架构。以一个小型制造企业为例,其财务管理系统涵盖了账务处理、报表生成、预算管理等功能。由于企业规模较小,业务流程相对简单,采用单体架构可以满足企业的日常管理需求。开发和维护成本较低,企业内部的 IT 人员能够轻松应对系统的日常运维工作。

八、系统整体框架代码举例

以简单的Java分层式单体架构为例

(一)表示层(以JSP页面为例)

<%@ page contentType="text/html; charset=UTF - 8" %>
<html>
<head><title>图书馆管理系统 - 图书查询</title>
</head>
<body><h1>图书查询</h1><form action="bookQueryServlet" method="post"><label for="bookTitle">图书标题:</label><input type="text" id="bookTitle" name="bookTitle"><br><input type="submit" value="查询"></form>
</body>
</html>

(二)业务逻辑层(BookQueryService.java)

import java.util.List;public class BookQueryService {private BookDao bookDao;public BookQueryService(BookDao bookDao) {this.bookDao = bookDao;}public List<Book> queryBooksByTitle(String title) {return bookDao.getBooksByTitle(title);}
}

(三)数据访问层(BookDao.java)

import java.util.List;public interface BookDao {List<Book> getBooksByTitle(String title);
}// 假设的数据库连接类
class DatabaseConnection {// 数据库连接相关代码
}// 实现BookDao接口的类
class BookDaoImpl implements BookDao {@Overridepublic List<Book> getBooksByTitle(String title) {// 数据库查询逻辑,假设使用JDBCDatabaseConnection connection = new DatabaseConnection();// 执行查询并返回结果return null;}
}

以 Java Spring Boot 为例)

        下面是一个简单的基于 Spring Boot 的单体架构 Web 应用示例,实现了一个用户管理模块的基本功能,包括用户注册和查询。​

项目结构​

src/​├── main/​│ ├── java/​│ │ └── com/​│ │ └── example/​│ │ ├── config/​│ │ │ └── WebMvcConfig.java​│ │ ├── controller/​│ │ │ └── UserController.java​│ │ ├── model/​│ │ │ └── User.java​│ │ ├── repository/​│ │ │ └── UserRepository.java​│ │ ├── service/​│ │ │ └── UserService.java​│ │ └── Application.java​│ └── resources/​│ ├── application.properties​│ └── static/​│ └── index.html​└── test/​└── java/​└── com/​└── example/​└── ApplicationTests.java​

User 模型类​

package com.example.model;​import javax.persistence.Entity;​import javax.persistence.GeneratedValue;​import javax.persistence.GenerationType;​import javax.persistence.Id;​​@Entity​public class User {​@Id​@GeneratedValue(strategy = GenerationType.IDENTITY)​private Long id;​private String username;​private String password;​​// Getters and Setters​public Long getId() {​return id;​}​​public void setId(Long id) {​this.id = id;​}​​public String getUsername() {​return username;​}​​public void setUsername(String username) {​this.username = username;​}​​public String getPassword() {​return password;​}​​public void setPassword(String password) {​this.password = password;​}​}​​

User 仓库接口​

package com.example.repository;​​import com.example.model.User;​import org.springframework.data.jpa.repository.JpaRepository;​​public interface UserRepository extends JpaRepository<User, Long> {​}​

User 服务类​

package com.example.service;​import com.example.model.User;​import com.example.repository.UserRepository;​import org.springframework.beans.factory.annotation.Autowired;​import org.springframework.stereotype.Service;​​@Service​public class UserService {​@Autowired​private UserRepository userRepository;​​public User saveUser(User user) {​return userRepository.save(user);​}​​public User findUserById(Long id) {​return userRepository.findById(id).orElse(null);​}​}​

User 控制器类​

package com.example.controller;​import com.example.model.User;​import com.example.service.UserService;​import org.springframework.beans.factory.annotation.Autowired;​import org.springframework.web.bind.annotation.*;​​@RestController​@RequestMapping("/users")​public class UserController {​@Autowired​private UserService userService;​​@PostMapping("/register")​public User registerUser(@RequestBody User user) {​return userService.saveUser(user);​}​​@GetMapping("/{id}")​public User getUserById(@PathVariable Long id) {​return userService.findUserById(id);​}​}​

应用主类​

package com.example;​​import org.springframework.boot.SpringApplication;​import org.springframework.boot.autoconfigure.SpringBootApplication;​​@SpringBootApplication​public class Application {​public static void main(String[] args) {​SpringApplication.run(Application.class, args);​}​}​

        这个简单的示例展示了一个单体架构 Web 应用的基本结构,各个模块(模型、仓库、服务、控制器)协同工作,实现了用户管理的部分功能。

九、未来发展趋势

        随着技术的不断发展,单体架构虽然在一些场景下仍然会被使用,但也在逐渐向混合架构发展。例如,在大型企业应用中,可能会将一些核心的、不易拆分的功能保留在单体架构部分,而将一些边缘的、需要独立扩展或频繁更新的功能拆分成微服务或者Serverless函数。同时,容器化技术也为单体架构的部署和管理提供了新的思路,通过将单体应用容器化,可以提高其可移植性和资源利用率。另外,为了提高单体架构的可维护性,代码模块化和自动化测试技术也会不断得到加强。

        尽管面临着诸多挑战,但单体架构在未来仍有其存在的价值。在一些特定场景下,如小型项目、对成本和开发速度要求极高的初创业务、功能简单且不需要频繁扩展的内部工具等,单体架构依然是一个不错的选择。同时,随着技术的发展,单体架构也在不断演进。例如,通过采用容器化技术(如 Docker),可以提高单体应用的部署效率和可移植性;利用云原生技术,将单体应用更好地融入云环境,享受云服务带来的弹性和便捷。此外,结合一些现代化的开发理念和工具,如微前端架构,可以在一定程度上缓解单体架构在大型项目中面临的可维护性和扩展性问题。未来,单体架构将与其他新型架构相互补充,共同为软件系统的构建提供多样化的选择。​

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/35835.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[C++初阶] :从C到C++

目录 C发展史&#xff0c;C语言的特性C新增关键字namespace关键字C语言的命名缺陷&#xff08;重定义现象&#xff09;域与指定访问操作符 “::”命名空间域详解namespace std C的输入与输出函数重载什么是重载,重载的几种常见形态重载的作用注意不构成重载的情况 缺省参数1.全…

[快乐学坊management_1] With Cursor | Mysql设计 | 服务接口设计与开发

目录 数据库设计流程 三张表 测试 接口设计 部门管理接口文档 1. 查询所有部门 2. 新增部门 ⭕3. 根据ID查询部门 4. 修改部门 5. 删除部门 &#xff08;部门分页条件查询&#xff09; 错误响应示例 接口设计规范 服务端开发 接口开发 数据库设计流程 01 明确业…

实用插件推荐 -------- 一个可以将任意语言(python、C/C++、go、java等)的程序转换为汇编语言的小插件

链接为&#xff1a; Compiler Explorer 界面&#xff1a; 参考自&#xff1a;如何获取虚函数表及内存分析_com的虚函数表怎么寻找-CSDN博客

vue学习八

十七 组件通信方式 1 props 父传子 //父组件 <script setup>//book来源省略import Subview1 from ./Subview1.vue;function updatebook(updatetimes){book.value.updatetimes updatetimes} </script> <template><Subview1 :book"book" :upd…

51单片机的寻址方式(完整)

目录 一、立即数寻址 二、直接寻址 三、寄存器寻址 四、寄存器间接寻址 五、变址寻址 六、位寻址 七、指令寻址 &#xff08;一&#xff09;绝对寻址 &#xff08;二&#xff09;相对寻址 在 51 单片机中&#xff0c;寻址方式是指在执行指令时&#xff0c;CPU 寻找操作…

每日一题:动态规划

如题&#xff08;基础题&#xff09;&#xff1a; 经典的爬楼梯问题&#xff0c;先从递归想起&#xff1b; class Solution { public:int climbStairs(int n) {if(n1)return 1;if(n2)return 2;return climbStairs(n-1)climbStairs(n-2);} }; 之后可以想办法&#xff08;如哈希…

【论文阅读】FairCLIP - 医疗视觉语言学习中的公平性提升

FairCLIP - 医疗视觉语言学习中的公平性提升 1.研究背景与动机2.核心贡献3.方法论细节4.实验结果与洞见5.总结 FairCLIP: Harnessing Fairness in Vision-Language Learning FairCLIP - 医疗视觉语言学习中的公平性提升 Accepted by CVPR2024 github:链接 1.研究背景与动机…

Linux 入门:权限的认识和学习

目录 一.shell命令以及运行原理 二.Linux权限的概念 1.Linux下两种用户 cannot open directory .: Permission denied 问题 2.Linux权限管理 1).是什么 2).为什么&#xff08;权限角色目标权限属性&#xff09; 3).文件访问者的分类&#xff08;角色&#xff09; 4).文…

大语言模型的压缩技术

尽管人们对越来越大的语言模型一直很感兴趣&#xff0c;但MistralAI 向我们表明&#xff0c;规模只是相对而言的&#xff0c;而对边缘计算日益增长的兴趣促使我们使用小型语言获得不错的结果。压缩技术提供了一种替代方法。在本文中&#xff0c;我将解释这些技术&#xff0c;并…

Java高频面试之集合-14

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;为什么 HashMap 的容量是 2 的倍数呢&#xff1f; HashMap的容量被设计为2的幂次&#xff0c;主要基于以下原因&#xff…

TreelabPLMSCM数字化供应链解决方案0608(61页PPT)(文末有下载方式)

详细资料请看本解读文章的最后内容。 资料解读&#xff1a;TreelabPLMSCM 数字化供应链解决方案 0608 在当今快速变化的市场环境中&#xff0c;企业面临着诸多挑战&#xff0c;Treelab 数智化 PLM_SCM 行业解决方案应运而生。该方案聚焦市场趋势与行业现状&#xff0c;致力于解…

Docker搭建MySQL主从服务器

一、在主机上创建MySQL配置文件——my.cnf master服务器配置文件路径&#xff1a;/data/docker/containers/mysql-cluster-master/conf.d/my.cnf slave服务器配置文件路径&#xff1a; /data/docker/containers/mysql-cluster-master/conf.d/my.cnf master服务配置文件内容 …

JS逆向案例-HIKVISION-视频监控的前端密码加密分析

免责声明 本文仅为技术研究与渗透测试思路分享,旨在帮助安全从业人员更好地理解相关技术原理和防御措施。任何个人或组织不得利用本文内容从事非法活动或攻击他人系统。 如果任何人因违反法律法规或不当使用本文内容而导致任何法律后果,本文作者概不负责。 请务必遵守法律…

SENT接口

文章目录 前言SENT接口简介物理层数据链路层编码方式帧结构消息格式短串行消息格式增强型串行消息格式 CRC校验和CRC4CRC6 错误检测机制 IP 设计结构框图接口设计上板验证 前言 本文参考标准《SAE J2716_201604》。 SENT接口 简介 SENT&#xff08;Single Edge Nibble Tran…

Qt-搭建开发环境

1.环境搭建 开发工具概述&#xff1a; Qt ⽀持多种开发⼯具&#xff0c;其中⽐较常⽤的开发⼯具有&#xff1a;Qt Creator、Visual Studio、Eclipse. 1.1Qt Creator Qt Creator 是⼀个轻量级的跨平台集成开发环境&#xff08;IDE&#xff09;&#xff0c;专为使⽤ Qt 框架进…

Odoo18 Http鉴权+调用后端接口

最近在调研Odoo18&#xff0c;包括它的前后端原理、源码等。发现官方的开发文档并不十分实用&#xff0c;比如标题这种简单的实用需求&#xff0c;竟然浪费了一点时间&#xff0c;特此记录。 官方文档&#xff1a;External API — Odoo 18.0 documentation 前提&#xff1a;首…

【第13节】windows sdk编程:GDI编程

目录 一、GDI 概述 二、设备环境概念 三、使用 GDI 绘图对象 四、使用 GDI 坐标系统 五、使用GDI绘图 5.1 输出文字 5.2 画点和线 5.3 画矩形框、圆和多边形 5.4 画位图和图标 5.5 双缓冲技术 六、综合代码示例 一、GDI 概述 Windows 应用程序不支持标准输出函数&am…

离开页面取消请求

前言 上一篇文章我们处理了axios的重复请求问题axios重复请求&#xff0c;今天来说一下如何在离开某个页面的时候将正在发送的请求取消掉 开始 基于上一篇的axios封装&#xff0c;当我们在编写某个页面的请求的时候 import request from /request/index;export const test2…

C++输入输出流第一弹:标准输入输出流 详解(带测试代码)

目录 C输入输出流 流的四种状态&#xff08;重点&#xff09; 标准输入输出流 标准输入流 逗号表达式 1. 逗号表达式的基本规则 示例 2. 图片中的代码分析 关键点解析 3. 常见误区 误区 1&#xff1a;逗号表达式等同于逻辑与 && 误区 2&#xff1a;忽略输入…

Z 轴热膨胀系数:PCB 可靠性的关键因素与选材策略

在电子设备小型化与高性能化的趋势下&#xff0c;PCB&#xff08;印刷电路板&#xff09;的可靠性成为决定产品寿命的核心因素。其中&#xff0c;Z 轴热膨胀系数&#xff08;α2/z-CTE&#xff09;作为板材的关键参数&#xff0c;直接影响多层板的层间结合力、焊点稳定性及整体…