概述
这是整个 SpringCloud 模块的导引篇。它不讲某一个组件的接口怎么调,而是先把"微服务到底想解决什么、SpringCloud 里的这一堆组件各自负责哪一段、按什么顺序学"讲清楚——先有地图再走路,后面十几篇才不至于变成一堆互不相干的 API 堆砌。
纲要
- 为什么要学微服务:求职、企业开发、并发增长、需求快速迭代四条现实理由
- 单体架构在规模上撑不住的三个痛点
- 微服务解决了老问题,又引入了哪些新问题(服务发现、远程调用、分布式配置、统一入口)
- SpringCloud 知识地图:组件按"解决什么问题"分层串起来
- SpringCloud 与 SpringBoot 的分工和版本对应关系(Hoxton.SR10 ↔ 2.3.9.RELEASE)
- 本模块组件与能力对照表
- 贯穿全模块的示例工程 cloud-demo 结构预览
- 学习路径建议:哪些必须先动手、哪些可以后置
- 下一篇预告
为什么要学微服务
把理由拆开看,其实就四类,前两类关于你,后两类关于企业。
求职角度:Java 后端面试里微服务是必问题。SpringCloud、注册中心、网关、熔断这些词说不上来,简历基本进不了下一轮。这不是课程宣传,是岗位 JD 里的硬门槛。
开发角度:企业项目现在极少有纯单体的了,中大型系统基本都是拆分后的多服务。进公司第一天就要在服务群里找别人的接口文档,不会微服务等于不会干活。这个模块除了讲微服务本身,还会讲微服务开发中会踩的各种坑和对应方案——所以学完拿到手的是一整套解决方案,不只是几个注解。
企业角度一,扛并发:互联网用户规模摆在那儿,一台 Tomcat 撑不住百万级并发,靠加机器也不是简单堆叠就能解决,得先把系统拆开,每个模块独立部署、独立扩容。微服务是应对高并发的前提。
企业角度二,扛变化:业务需求一直在变,单体项目所有功能耦合在一起,改一个模块要反复评估对其它模块的影响,上线一次提心吊胆。拆成服务之后,服务间耦合度低,改一个服务基本不用管别人,迭代效率高,这才撑得起敏捷开发。
单体架构撑不住的三个痛点
先把"为什么必须拆"说透。单体架构把全部业务打成一个包部署,好处是架构简单、部署成本低,做学生管理系统这种小项目完全够用。一旦规模上来,问题集中爆发在三处:
| 痛点 | 具体表现 |
|---|---|
| 编译部署慢 | 代码量堆到几十万行,改一行日志也要全量编译打包,一次构建十几分钟起步,本地启动动辄几十秒 |
| 模块边界模糊 | 所有功能写在同一个工程里,包结构靠人自觉维护。时间一长,订单代码调用户代码、用户代码反向调订单代码,形成循环依赖,谁也不敢动 |
| 无法按模块扩容 | 秒杀场景只有下单接口压力大,但单体只能整个应用一起扩容,跟着被放大的还有根本没人访问的管理后台 |
拆成微服务后,一个功能模块一个服务,大型企业里成百上千个服务都正常,每个服务独立部署,并发能力自然上去了。
但拆开不是免费的午餐。原来一个方法调用搞定的事,现在变成了跨网络的 HTTP 请求,紧接着冒出来一串新问题:
- 服务地址怎么找?IP 和端口写死在代码里,服务换机器就全崩
- 有多个实例时调哪一个?总不能手动挑
- 某个实例挂了怎么知道?请求打过去一直超时才反应过来
- 几十个服务的配置文件散落在各处,改一个数据库地址要挨个改
- 用户该从哪个入口进来?每个服务都对外暴露端口、各自做鉴权显然不现实
- 部署几十上百台服务器靠人手一个个操作,工作量巨大还容易出错
微服务的价值不在于"拆",而在于拆完之后有一套东西来管理这些新问题。SpringCloud 就是这套东西的集合。
从问题到技术:一张对应表
下面这张表是本模块的骨架,后面每一章基本都在填其中一行。
| 新问题 | 对应技术 | 定位 |
|---|---|---|
| 服务之间怎么调用 | RestTemplate / Feign | 发起远程 HTTP 调用,Feign 让调用像调本地接口 |
| 服务地址从哪来、怎么管理调用关系 | 注册中心(Eureka / Nacos) | 服务启动时上报自己的地址,调用方按服务名拉取实例列表 |
| 多个实例怎么选 | Ribbon / Spring Cloud LoadBalancer | 拿到实例列表后按算法挑一个,实现负载均衡 |
| 某个实例是不是还活着 | 心跳机制 | 实例定期上报状态,超时未上报就从列表里剔除 |
| 一堆配置散落各处 | 配置中心(Nacos Config) | 配置集中存放,支持热更新,改完不用重启服务 |
| 用户从哪进来、谁来鉴权 | 服务网关(Gateway) | 统一入口,负责路由、鉴权、限流、跨域 |
| 某个服务挂了会不会拖垮全链路 | 熔断降级 / 服务保护 | 故障服务快速失败,避免级联失败拖垮整条调用链 |
| 出问题怎么定位 | 分布式日志、链路追踪与系统监控 | 汇总各服务日志、监控每个节点的 CPU/内存/响应耗时 |
| 上百台机器怎么部署 | 容器化与持续集成(Docker、K8s) | 自动化打包成镜像、编排部署,替代人工逐台操作 |
表里最后几行的缓存、消息队列、分布式搜索、DevOps 属于更外层的微服务解决方案,本模块先建立印象,具体技术会在对应专题里展开。
SpringCloud 知识地图
把上面的技术按调用链串起来,就是一个请求从进入系统到落库的完整路径。
每一层用一句话说清它存在的理由:
- 服务拆分与远程调用:不拆就没法独立扩容;拆了之后方法调用变成网络请求,得有人把 HTTP 调用封装成"像调本地方法一样"。没有它,就得手写 HttpClient、自己拼 URL、自己处理 JSON 和异常。
- 注册中心:没有它,调用方只能把提供方的 IP 和端口写死在配置文件里,服务扩缩容、换机器、加实例都要改代码重新发版。有了它,服务按名字找,地址是动态的。
- 负载均衡:没有它,一个服务部署了三个实例,请求全打到第一个上,等于白扩容。有了它,请求按算法分散到各实例。
- 配置中心:没有它,几十个服务的配置散落在各自仓库,改一个公共参数要挨个提交、挨个重启。有了它,配置集中管理,还能在不停机的情况下热更新。
- 服务网关:没有它,每个微服务都要对外暴露端口、各自实现鉴权逻辑,前端还要记住一堆地址。有了它,所有流量走一个入口,鉴权、限流、跨域这些横切关注点收在一处,就像小区门口的保安——先看你是谁、再问你要找谁,然后告诉你往哪走。
- 服务保护:没有它,链路上任何一个服务变慢或挂掉,调用方线程会被大量阻塞,故障沿着调用链级联扩散,最终整个系统雪崩。有了它,故障服务被快速熔断,请求走降级逻辑,损失可控。
SpringCloud 与 SpringBoot 的关系
这两个名字经常被混在一起,分工其实很清楚:
- SpringBoot解决"单个服务怎么快速搭起来"——自动配置、内嵌 Tomcat、starter 依赖,让一个独立服务几分钟就能跑起来。
- SpringCloud解决"多个服务之间怎么协同"——它把注册中心、网关、负载均衡这些组件集成起来,底层基于 SpringBoot 的自动装配能力实现,所以用起来也是加依赖、加注解、写配置。
关系是前者是地基,后者是地基上盖的楼。这也意味着两者版本必须匹配,SpringCloud 的每个大版本都锁定了对应的 SpringBoot 版本区间,配错了启动就会报版本不兼容。
| SpringCloud 版本 | 对应 SpringBoot 版本 |
|---|---|
| Hoxton.SR10(本模块使用) | 2.3.x(示例工程实际用 2.3.9.RELEASE) |
| Greenwich | 2.1.x |
| Finchley | 2.0.x |
| 2020.x 及以后 | 2.4.x 往上(命名规则从地名改为年份) |
版本写在哪?在父工程的pom.xml里用属性统一声明,子模块不写版本号,避免各写各的。
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.itcast.demo</groupId><artifactId>cloud-demo</artifactId><version>1.0</version><packaging>pom</packaging><modules><module>user-service</module><module>order-service</module></modules><!-- 父工程直接继承 spring-boot-starter-parent,锁定 SpringBoot 版本 --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEASE</version><relativePath/></parent><properties><java.version>1.8</java.version><spring-cloud.version>Hoxton.SR10</spring-cloud.version><mysql.version>5.1.47</mysql.version><mybatis.version>2.1.1</mybatis.version></properties><dependencyManagement><dependencies><!-- 用 import 方式引入 SpringCloud 的 BOM,子模块即可省略版本号 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.version}</version></dependency></dependencies></dependencyManagement></project>有个坑值得先提一句:dependencyManagement只是"声明版本",不会真的引入依赖。子模块必须自己写<dependency>才会生效,很多人第一次配完发现类找不到,就是漏了这一步。
本模块组件与能力对照表
把全模块要动手的组件列出来,方便对照后面各章的归属。
| 组件 | 定位 | 解决的问题 | 后续章节 |
|---|---|---|---|
| RestTemplate | Spring 自带的 HTTP 客户端 | 手写远程调用的起点,理解"调用变成了网络请求" | 服务拆分与远程调用 |
| Feign | 声明式 HTTP 客户端 | 把远程调用写成接口,不用手拼 URL 和解析响应 | Feign 远程调用 |
| Eureka | 注册中心(Netflix) | 服务注册与发现,地址不再硬编码 | 认识微服务 |
| Nacos | 注册中心 + 配置中心(阿里) | 国内主流方案,含集群分级、权重、环境隔离 | Nacos 注册中心 |
| Ribbon | 客户端负载均衡 | 从实例列表里按算法选一个实例 | Ribbon 负载均衡 |
| Spring Cloud LoadBalancer | 新一代负载均衡 | 替代进入维护期的 Ribbon | 版本升级说明 |
| Nacos Config | 配置中心 | 配置集中管理与热更新 | 配置管理 |
| Gateway | 服务网关 | 统一入口、路由转发、鉴权、限流、跨域 | 网关快速入门 |
| 熔断降级组件 | 服务保护 | 防级联失败与雪崩(本模块侧重概念与场景) | 服务保护 |
贯穿全模块的示例工程 cloud-demo
这套课程不是每章换一个 demo,而是从头到尾围绕同一个工程cloud-demo迭代。刚开始它只有两个服务,随着章节推进逐步长出注册中心、网关、Feign 客户端。
cloud-demo/ ├── pom.xml # 父工程:统一管理 SpringCloud / SpringBoot / MyBatis 版本 ├── user-service/ # 用户微服务(端口 8081),对外暴露 Restful 接口 │ ├── pom.xml │ └── src/main/ │ ├── java/cn/itcast/user/ │ │ ├── UserApplication.java │ │ ├── mapper/UserMapper.java │ │ ├── pojo/User.java │ │ ├── service/UserService.java │ │ └── web/UserController.java │ └── resources/application.yml ├── order-service/ # 订单微服务(端口 8080),查询订单时需要调用户服务 │ ├── pom.xml │ └── src/main/ │ ├── java/cn/itcast/order/ │ │ ├── OrderApplication.java │ │ ├── mapper/OrderMapper.java │ │ ├── pojo/{Order.java, User.java} │ │ ├── service/OrderService.java │ │ └── web/OrderController.java │ └── resources/application.yml ├── feign-api/ # 后置章节新增:Feign 客户端与公共 pojo 抽成独立模块 │ ├── pom.xml │ └── src/main/java/cn/itcast/feign/{clients,config,pojo}/ ├── eureka-server/ # 后置章节新增:注册中心服务端(端口 10086) │ ├── pom.xml │ └── src/main/ │ ├── java/cn/itcast/eureka/EurekaApplication.java │ └── resources/application.yml └── gateway/ # 后置章节新增:服务网关,所有外部请求的统一入口 ├── pom.xml └── src/main/ ├── java/cn/itcast/gateway/GatewayApplication.java └── resources/application.yml拆分遵循三条原则,后面写代码时会反复用到:
- 不同微服务不重复开发相同业务,用户相关的逻辑只放在 user-service
- 数据独立,order-service 不能直接查 user 库,两张表各归各的服务管
- 需要别人的数据时,只能通过对方暴露的 Restful 接口拿
第一条远程调用的代码长这样,先注册一个RestTemplate到 Spring 容器,再在订单服务里用它去请求用户服务:
packagecn.itcast.order;importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.context.annotation.Bean;importorg.springframework.web.client.RestTemplate;@MapperScan("cn.itcast.order.mapper")@SpringBootApplicationpublicclassOrderApplication{publicstaticvoidmain(String[]args){SpringApplication.run(OrderApplication.class,args);}/** * 把 RestTemplate 交给 Spring 管理,后续直接注入即可发起 HTTP 调用。 * 注意:这里地址还是写死的 http://localhost:8081,注册中心那一章会把它换成服务名。 */@BeanpublicRestTemplaterestTemplate(){returnnewRestTemplate();}}这段代码里localhost:8081就是"地址硬编码"的活标本。等注册中心上完,这里会被替换成http://userservice/user/{id},Ribbon 负责把userservice翻译成真实 IP 和端口。
学习路径建议
知识点多且杂,按"企业使用频率 + 实用性"排优先级,别按目录顺序硬啃。
必须先动手、而且建议边写边理解的三块:
- 服务拆分与远程调用。这是所有后续内容的载体,先感受单体调用变成 HTTP 请求之后到底多了哪些麻烦(超时、序列化、异常处理),否则后面每个组件都是在解决"不存在的问题"。
- 注册中心。理解服务注册、服务拉取、心跳三个动作,以及为什么调用方可以只写服务名。Eureka 和 Nacos 都过一遍,重点看它们对临时实例、健康检测的处理差异。
- 远程调用与负载均衡的配合。手动起两个 user-service 实例,观察请求怎么在两个端口之间轮询,这个"看得见的效果"比背算法名称有用得多。
可以后置的:
- 配置管理。它是运维友好型能力,本地开发感受不深,等有了多环境(dev/test/prod)需求再重点看。
- 服务网关。独立于服务拆分之外,晚一点学不影响前面的理解。
- 集群搭建与高可用部署。偏向运维,面试偶尔问,实际开发中通常有专门的部署平台,放最后。
- 熔断降级、分布式事务、分布式日志与链路追踪。这类更贴近原理、使用频率相对低,先会用再研究。
按这个顺序走,基本能做到"每学一章,手上的 cloud-demo 就真的变复杂一点",而不是攒一堆跑不起来的示例代码。
下一篇预告
下一篇从最基础的地方开始:认识微服务与服务架构演变。会讲清楚单体架构、分布式架构、微服务这三者各自的定义和优缺点,为什么说"微服务是一种经过良好架构设计的分布式架构方案",以及 SpringCloud 与 SpringCloudAlibaba 在服务治理上的技术选型差异。
这一篇是导引,只给地图和路线,不展开任何组件的技术细节——具体怎么引依赖、怎么改配置、监控页面上该看到什么,都放到对应章节里讲。
官方文档
- Spring Cloud 官网
- Nacos 官网
- Spring Cloud Alibaba
总结
微服务不是"把项目拆小"这么简单,拆分本身只是起点,真正的成本在于拆完之后一大堆跨网络、跨进程的新问题。SpringCloud 的价值就在于它把这些问题的解法打成了标准件:注册中心管地址、负载均衡管分流、配置中心管参数、网关管入口、熔断管故障隔离。
学这一块的关键是先建立"问题 → 技术"的映射,遇到需求时能反应出该用哪个组件,而不是先记住一堆注解名字。示例工程 cloud-demo 会从头用到尾,建议自己动手跑一遍,两个 user-service 实例加一个注册中心,比看十遍原理图都直观。
版本别配错,Hoxton.SR10 配 SpringBoot 2.3.9.RELEASE,这是本模块全篇的基准。