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

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

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

三、单体架构发展历史
早期的软件系统相对简单,单体架构因其简单直接的构建方式而被广泛采用。在计算机技术发展的初期,硬件资源有限,开发人员更倾向于构建紧凑、一体化的应用。随着业务需求的不断增长,单体架构也在不断扩展,但基本的架构模式在很长一段时间内保持不变。例如,许多传统的企业级应用,如早期的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;@Entitypublic class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String username;private String password;// Getters and Setterspublic 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;@Servicepublic class UserService {@Autowiredprivate 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 {@Autowiredprivate 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;@SpringBootApplicationpublic class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
这个简单的示例展示了一个单体架构 Web 应用的基本结构,各个模块(模型、仓库、服务、控制器)协同工作,实现了用户管理的部分功能。
九、未来发展趋势
随着技术的不断发展,单体架构虽然在一些场景下仍然会被使用,但也在逐渐向混合架构发展。例如,在大型企业应用中,可能会将一些核心的、不易拆分的功能保留在单体架构部分,而将一些边缘的、需要独立扩展或频繁更新的功能拆分成微服务或者Serverless函数。同时,容器化技术也为单体架构的部署和管理提供了新的思路,通过将单体应用容器化,可以提高其可移植性和资源利用率。另外,为了提高单体架构的可维护性,代码模块化和自动化测试技术也会不断得到加强。
尽管面临着诸多挑战,但单体架构在未来仍有其存在的价值。在一些特定场景下,如小型项目、对成本和开发速度要求极高的初创业务、功能简单且不需要频繁扩展的内部工具等,单体架构依然是一个不错的选择。同时,随着技术的发展,单体架构也在不断演进。例如,通过采用容器化技术(如 Docker),可以提高单体应用的部署效率和可移植性;利用云原生技术,将单体应用更好地融入云环境,享受云服务带来的弹性和便捷。此外,结合一些现代化的开发理念和工具,如微前端架构,可以在一定程度上缓解单体架构在大型项目中面临的可维护性和扩展性问题。未来,单体架构将与其他新型架构相互补充,共同为软件系统的构建提供多样化的选择。
相关文章:
【软件系统架构】单体架构
一、引言 在软件开发的漫长历程中,架构的选择一直是至关重要的决策。单体架构作为一种经典的架构模式,曾经在许多项目中发挥着不可替代的作用。虽然如今微服务等架构逐渐流行,但理解单体架构对于深入掌握软件架构体系仍然有着重要意义。 二、…...
【求助】【建议放弃】【谷粒商城版】Kubernetes
本文作者: slience_me 文章目录 Kubernetes【谷粒商城版】【建议放弃】1. docker安装2. kubernetes安装前3. kubeadm,kubelet,kubectl3.1 简介kubeadmkubeletkubectl常用指令 3.2 安装3.3 kubeadm初始化3.4 加入从节点(工作节点)3.5 安装Pod网络插件(CNI…...
uniapp 实现微信小程序电影选座功能
拖动代码 /*** 获取点击或触摸事件对应的座位位置* 通过事件对象获取座位的行列信息* param {Event|TouchEvent} event - 点击或触摸事件对象* returns {Object} 返回座位位置对象,包含行(row)和列(col)信息,若未找到有效位置则返回 {row: -1, col: -1}*…...
python+flask实现360全景图和stl等多种格式模型浏览
1. 安装依赖 pip install flask 2. 创建Flask应用 创建一个基本的Flask应用,并设置路由来处理不同的文件类型。 from flask import Flask, render_template, send_from_directory app Flask(__name__) # 设置静态文件路径 app.static_folder static app.r…...
IntelliJ 配置文件plugin.xml
在 IntelliJ IDEA 插件开发中,plugin.xml 是插件的配置文件,它包含了关于插件的所有基本信息、扩展点、依赖关系等。该文件使用 XML 格式进行定义。以下是 plugin.xml 中常见的元素及其用途: <idea-plugin><!-- 插件的基本信息 --&…...
C# Unity 唐老狮 No.10 模拟面试题
本文章不作任何商业用途 仅作学习与交流 安利唐老狮与其他老师合作的网站,内有大量免费资源和优质付费资源,我入门就是看唐老师的课程 打好坚实的基础非常非常重要: Unity课程 - 游习堂 - 唐老狮创立的游戏开发在线学习平台 - Powered By EduSoho C# 1. 内存中,堆和…...
数据库系统——规范化1NF~BCNF
数据库规范化完全指南:从零到BCNF,中学生也能秒懂!📚✨ 一、什么是数据库规范化? 科学定义 🔍 数据库规范化是通过一系列规则(范式)将数据库表结构分解为更小、更高效、无冗余的表…...
第十五届蓝桥杯2024JavaB组省赛试题A:报数游戏
简单的找规律题目。题目给得数列,第奇数项是20的倍数,第偶数项时24的倍数。题目要求第n 202420242024 项是多少。这一项是偶数,所以答案一定是24的倍数,并且偶数项的个数和奇数项的个数各占一半,所以最终的答案ans( n…...
Matlab 汽车二自由度转弯模型
1、内容简介 Matlab 187-汽车二自由度转弯模型 可以交流、咨询、答疑 2、内容说明 略 摘 要 本文前一部分提出了侧偏角和横摆角速度作为参数。描述了车辆运动的运动状态,其中文中使用的参考模型是二自由度汽车模型。汽车速度被认为是建立基于H.B.Pacejka的轮胎模…...
关于 2>/dev/null 的作用以及机理
每个进程都有三个标准文件描述符:stdin(标准输入)、stdout(标准输出)和stderr(标准错误)。默认情况下,stderr会输出到终端。使用2>可以将stderr重定向到其他地方,比如…...
学c++的人可以几天速通python?
学了俩天啊,文章写纸上了 还是蛮有趣的...
HTML,CSS,JavaScript
HTML:负责网页的结构(页面元素和内容)。 CSS:负责网页的表现(页面元素的外观、位置等页面样式,如:颜色、大小等)。 Javascript:负责网页的行为(交互效果)。 MDN前端开发文档(MDN Web Docs) HTML HTML(HyperText Markup Language):超文本标记语言超文本:超越了文本的…...
微信小程序面试内容整理-图片优化
在微信小程序中,图片优化是提升加载速度、节省网络带宽和提高用户体验的重要步骤。图片通常是小程序页面中的主要资源,合理的图片优化能显著提高小程序的性能,尤其是在用户网络状况较差的情况下。 1. 选择合适的图片格式 不同的图片格式有不同的特点,选择合适的格式能够有效…...
Rocky Linux 9.x 基于 kubeadm部署k8s 1.32
一、部署说明 1、主机操作系统说明 序号操作系统及版本备注1Rocky Linux release 9下载链接:https://mirrors.163.com/rocky/9.5/isos/x86_64/Rocky-9.5-x86_64-minimal.iso 2、主机硬件配置说明 作用IP地址操作系统配置关键组件k8s-master01192.168.234.51Rocky…...
【每日学点HarmonyOS Next知识】上下拉列表、停止无限循环动画、页面列表跟随列表滑动、otf字体、日期选择
1、HarmonyOS 实现只需要保留上拉加载更多,但是不需要下拉刷新? Refresh通过参数refreshing判断当前组件是否正在刷新,可以控制该参数变化来触发下拉刷新:https://developer.huawei.com/consumer/cn/doc/harmonyos-references-V5…...
解决git init 命令不显示.git
首先在自己的项目代码右击 打开git bash here 输入git init 之后自己的项目没有.git文件,有可能是因为.git文件隐藏了,下面是解决办法...
利用AI让数据可视化
1. 从问卷星上下载一份答题结果。 序号用户ID提交答卷时间所用时间来源来源详情来自IP总分1、《中华人民共和国电子商务法》正式实施的时间是()。2、()可以判断企业在行业中所处的地位。3、()是指店铺内有…...
神经网络微调技术解析
神经网络微调技术 微调(Fine-tuning)是迁移学习的核心技术,通过在预训练模型基础上调整参数,使其适应特定任务或领域。以下从传统方法、参数高效微调(PEFT)、新兴技术三个维度展开,覆盖主流技术…...
WebLogic XMLDecoder反序列化漏洞(CVE-2017-10271)深度解析与实战复现
0x00 漏洞概述 CVE-2017-10271 是Oracle WebLogic Server WLS Security组件中的远程代码执行漏洞。攻击者通过构造恶意XML请求,利用XMLDecoder反序列化机制绕过安全验证,最终实现服务器权限接管。 影响版本 WebLogic 10.3.6.0WebLogic 12.1.3.0WebLog…...
解决qt中自定插件加载失败,不显示问题。
这个问题断断续续搞了一天多,主要是版本不匹配问题。 我们先来看下 Based on Qt 6.6.0 → 说明 Qt Creator 本身 是基于 Qt 6.6.0 框架构建的。MSVC 2019, 64-bit → 说明 Qt Creator 是使用 Microsoft Visual C 2019 编译器(64 位) 编译的。…...
Git 面试问题,解决冲突
1.问题描述 在多人协作开发中,当多个开发者在同一文件的同一部分进行修改并提交时,Git 无法自动合并这些更改,从而产生代码冲突(Conflict)。冲突的代码会被 Git 标记出来,需要开发者手动解决。 冲突原因 多…...
Apache Shiro 使用教程
Apache Shiro 使用教程 Apache Shiro是一个强大且灵活的开源安全框架,主要用于处理身份验证(Authentication)、授权(Authorization)、加密(Cryptography)和会话管理(Session Manage…...
用maven生成springboot多模块项目
用Maven生成Spring Boot多模块项目,可以按照以下步骤操作: 1. 创建父项目 首先,使用Maven的archetype插件创建一个空的Maven项目作为父项目。打开终端,执行以下命令: mvn archetype:generate -DgroupIdcom.example -…...
【最佳实践】Go 状态模式
设计思路 状态模式的核心在于将对象的行为封装在特定的状态类中,使得对象在不同的状态下表现出不同的行为。每个状态实现同一个接口,允许对象在运行时通过改变其内部状态对象来改变其行为。状态模式使得状态转换更加明确,并且易于扩展新的状…...
智慧社区3.0
项目介绍: 此项目旨在推动成都市探索**超大城市社区发展治理新路**,由三个实验室负责三大内容 1、**研发社区阵地空间管理模块**:AI算法实现态势感知(如通过社区图片和视频、文本,对环境 空间质量、绿视率、安全感分…...
C#语法基础总结
输入和输出 输入 Console.Read(); 从屏幕读取一个字符,并返回该字符所对应的整型数字 Console.ReadLine(); 从屏幕读取一串字符,并返回该字符串 输出 Console.WriteLine(); 输出内容,并换行 Console.Write(); 输出内容,不换行…...
Springboot+Vue登录、注册功能(含验证码)(后端!)
我们首先写一个接口,叫login!然后对传入一个user,因为我们前端肯定是要传过来一个user,然后我们后端返回一个user,因为我们要根据这个去校验!我们还引入了一个hutool的一个东西,在pom文件里面引…...
深入理解 HTML 中的<div>和元素:构建网页结构与样式的基石
一、引言 在 HTML 的世界里,<div>和元素虽看似普通,却扮演着极为关键的角色。它们就像网页搭建过程中的万能积木,能够将各种 HTML 元素巧妙地组合起来,无论是构建页面布局,还是对局部内容进行样式调整ÿ…...
搞定python之八----操作mysql
本文是《搞定python》系列文章的第八篇,讲述利用python操作mysql数据库。相对来说,本文的综合性比较强,包含了操作数据库、异常处理、元组等内容,需要结合前面的知识点。 1、安装mysql模块 PyMySql模块相当于数据库的驱动&#…...
游戏立项时期随笔记录(1)
模拟经营的项目还没有完全结束,这几天又有可能涉及到一个新项目。感想随笔记录一下,防止忘记。今天一天整理这个,搞得今天没时间看数学和AI。 在 Unity3D 游戏前端主程序的立项时期,核心目标是明确技术方向、评估可行性、搭建基础…...
