从 Servlet 到 Spring Cloud:Java 后端技术演进全解析
从 Servlet 到 Spring Cloud:Java 后端技术演进全解析
Java后端技术的整条演进线是典型的问题驱动式迭代:上一阶段的方案解决了核心痛点,又会暴露出新的工程/架构问题,下一项技术针对性补位,最终形成从原生代码到微服务的完整技术体系。
一、 原生Servlet时代:Web开发的原始形态
前端发起 `/add` HTTP 请求后,请求首先送达独立部署的外部 Tomcat(Servlet 容器);Tomcat 会读取项目中的 `web.xml` 部署描述文件,通过路径匹配找到对应的 Servlet 实现类,实例化后调用对应方法执行业务逻辑,最终将结果返回前端。
这个阶段遵循「一个接口对应一个独立 Servlet 类」的开发模式:如果新增减法接口 `/de`,就必须新建一个 Servlet 实现类,同时在 `web.xml` 中补充一组 `<servlet>` 注册配置和一组 `<servlet-mapping>` 路径映射配置。接口数量越多,Servlet 类和配置项就越臃肿,同时每个 Servlet 里还要重复编写参数解析、响应头设置、JSON 转换等样板代码,开发效率极低,配置维护成本极高。
二、Spring + Spring MVC 时代:从开发范式上解决繁琐与耦合问题
针对原生 Servlet 时代「接口开发繁琐、代码强耦合」两大核心痛点,Spring 生态从 Web 层和业务层分别给出了解法,彻底重塑了 Java 企业级开发的模式。
第一,Spring MVC 统一请求分发,终结单接口单Servlet模式。
它通过一个全局的 `DispatcherServlet(前端控制器)`承接所有 HTTP 请求,替代了原本「一个接口一个 Servlet」的设计。请求进入容器后,由 `DispatcherServlet` 内部扫描 `@RequestMapping`、`@GetMapping` 等注解,自动匹配 Controller 中对应的业务方法,同时自动完成参数绑定、类型转换、JSON 序列化等通用工作。
带来的直接变化是:`web.xml` 只需要配置一次总入口 Servlet,后续新增接口仅需在 Controller 类中增加方法、加上路由注解即可,完全不需要新增 Servlet 类,也不用再修改 `web.xml`,Web 层的开发效率得到质的提升。
第二,IoC + AOP 实现业务代码彻底解耦,消灭重复样板代码。
- IoC(控制反转/依赖注入):把所有业务对象的创建、依赖装配、生命周期管理全部交给 Spring IoC 容器统一负责。各层代码只依赖接口、不绑定具体实现类,不需要手动 `new` 对象,容器会自动把依赖注入到位。这种设计完全符合开闭原则,更换业务实现时不需要修改调用方代码,同时也支持通过 Mock 对象隔离外部依赖,让单元测试更简单、更高效。
- AOP(面向切面编程):把事务、日志、权限校验、全局异常处理等与业务无关的「横切通用逻辑」从业务代码中完全剥离,通过切面统一配置、动态织入到目标方法中。大量通用能力仅需一个注解就能生效,彻底消灭了业务方法中重复的样板代码,让业务代码更纯粹、更易维护。
三、Spring Boot 时代:开箱即用,彻底简化配置与部署
原生 Spring 解决了代码层面的核心问题,但依然存在「依赖版本难对齐、配置文件繁琐、部署流程笨重」的工程化痛点。Spring Boot 在 Spring 框架的基础上做了一层工程化封装,核心理念是「约定大于配置」,目标是让开发者开箱即用,专注业务逻辑开发。
它的核心优化对应解决三类痛点:
第一,起步依赖(Starter,即场景依赖):场景化依赖打包,彻底解决版本冲突。
它把特定业务场景需要的所有依赖打包整合为一个 Starter 组件,比如引入 `spring-boot-starter-web` 一个依赖,就自动包含了 Spring MVC、内置 Tomcat、JSON 转换工具等完整 Web 开发所需的全部组件,无需逐个引入 Jar 包,大幅简化了 `pom.xml` 的配置。更核心的是,所有组件的版本都由官方测试验证,彻底解决了依赖版本不兼容的问题。
第二,自动配置:智能默认装配,消灭大量重复配置。
基于条件注解实现智能默认装配:只要引入了对应场景的 Starter,框架就会自动完成该场景的通用配置——比如引入 Web 场景就自动配置好 DispatcherServlet、静态资源映射、JSON 转换器;引入数据库场景就自动配置好数据源、事务管理器。绝大多数场景使用默认配置即可正常运行,需要自定义时仅需在 `application.yml` 中修改少量参数,彻底摆脱了原生 Spring 时代大量的配置文件。
第三,内置 Servlet 容器,告别外部容器部署。
默认内嵌 Tomcat 容器(也支持切换 Jetty、Undertow),项目可以直接打成可执行 Jar 包,无需单独安装、配置外部 Tomcat 容器,也不用再打 War 包部署到容器中,仅需一条 `java -jar` 命令就能启动项目,部署和本地调试的成本大幅降低。
> 注意:Spring Boot 不是替代 Spring 的新框架,它底层完全复用 Spring IoC + Spring MVC 的核心能力,只是做了工程化的封装与简化。它完美解决了单体应用的开发部署效率问题,但解决不了单体架构本身的规模瓶颈。
四、 Spring Cloud 时代:微服务分布式治理,支撑大规模业务扩展
当业务规模、团队规模持续扩大,单体 Spring Boot 应用会逐渐暴露出瓶颈:所有业务模块耦合在同一个项目中,代码臃肿维护难、全量发布迭代慢、只能整体扩容无法按需分配资源、单点故障会导致全业务不可用。
行业的解法是按业务域拆分单体,把一个大项目拆成多个独立开发、独立部署、独立扩容的小型 Spring Boot 服务(即微服务)。而 Spring Cloud 就是基于 Spring Boot 构建的一整套微服务分布式治理解决方案——它不替代 Spring Boot,而是解决服务拆分后衍生的一系列分布式工程问题。
拆分微服务后,会陆续出现一系列分布式架构特有的工程化问题,Spring Cloud 针对每个痛点都提供了对应的开箱即用组件,逐一解决:
第一,服务寻址问题。
痛点:服务拆分后分布在不同机器上,调用方如果硬编码对方的 IP 和端口,后续服务扩容、迁移、下线都要修改代码重新发布,维护成本极高。
对应解决方案:注册中心(Nacos / Eureka)
核心作用:相当于微服务集群的统一「通讯录」。所有服务启动时,都会自动向注册中心登记自己的服务名、IP 地址和端口号;服务之间发起调用时,只需要通过服务名就能动态查询到目标服务的所有可用地址,不需要写死任何 IP 端口。服务扩容、下线时注册中心会自动更新列表,调用方完全无感知,无需修改代码。
第二,多实例流量分配问题。
痛点:同一个服务部署了多台实例做高可用,如果请求始终只打在其中一台上,会出现单台负载过高、其他实例资源闲置的情况,也无法真正实现故障容灾。
对应解决方案:客户端负载均衡(Spring Cloud LoadBalancer)
核心作用:调用方从注册中心拿到服务实例列表后,会自动按照预设规则(默认轮询)把请求分摊到所有可用实例上,实现流量均匀分配;当某个实例出现故障时,也会自动将其从可用列表中剔除,请求自动切换到正常实例,保障服务高可用。
第三,服务雪崩问题。
痛点:当下游服务出现故障、响应超时或异常率飙升时,上游调用方的请求会持续堆积、占用连接资源,最终导致调用方自身也被拖垮;故障会沿着调用链层层扩散,最终引发整个集群的大面积瘫痪,也就是「服务雪崩」。
对应解决方案:熔断降级(Sentinel / Hystrix)
核心作用:相当于给每个服务加装了「保险丝」。当检测到下游服务的异常率、超时率达到预设阈值时,会自动触发熔断,短时间内不再向故障服务发起新的请求,直接返回预设的兜底结果。通过这种方式隔离故障节点,避免故障沿调用链扩散,保障整体系统的稳定性。
第四,入口分散与通用逻辑重复问题。
痛点:拆分后前端需要对接多个服务的独立地址,维护成本高;同时跨域、鉴权、限流、访问日志等通用能力,每个业务服务都要重复开发一遍,冗余工作多,也难以统一管控。
对应解决方案:服务网关(Spring Cloud Gateway)
核心作用:作为整个微服务集群的唯一流量入口,前端只需要对接网关一个地址。网关会根据请求路径规则,将流量精准转发到对应的后端服务;同时跨域配置、身份鉴权、接口限流、访问日志、黑白名单等通用能力,都可以统一在网关层实现,所有后端服务无需重复开发,实现全局统一管控。
第五,配置分散运维难问题。
痛点:当集群规模达到几十上百个服务时,每个服务独立维护配置文件,修改一个公共配置(比如数据库地址、功能开关)需要逐个修改、逐个重启服务,运维工作量极大,也容易出现配置不一致的问题。
对应解决方案:配置中心(Nacos Config / Spring Cloud Config)
核心作用:将所有服务的配置从本地项目中剥离,统一集中存储在配置中心管理。服务启动时会自动从配置中心拉取自身对应的配置;同时支持配置动态刷新,修改配置后无需重启服务就能实时生效,大幅降低了大规模集群的运维成本,也保证了配置的一致性。
第六,远程调用代码冗余问题。
痛点:服务间通过 HTTP 远程调用时,需要手动拼接 URL、设置请求头、序列化参数、解析响应结果、处理调用异常,每个接口都要编写大量重复的样板代码,且不同开发者的实现风格不统一,维护困难。
对应解决方案:声明式服务调用(OpenFeign)
核心作用:屏蔽了底层 HTTP 调用的所有细节,让开发者可以像调用本地方法一样调用远程服务。只需要定义一个 Java 接口,搭配对应的注解标注服务名和接口路径,框架就会自动生成实现代码,自动完成服务发现、负载均衡、请求发送、参数序列化、结果解析、异常处理等全流程工作,大幅简化了远程调用的开发成本。
第七,分布式故障排查难问题。
痛点:一次用户请求往往会跨越多层、多个服务,一旦出现接口报错或响应变慢,很难快速判断是哪个服务、哪段代码出了问题,排查故障像大海捞针,服务数量越多排查成本越高。
对应解决方案:分布式链路追踪(Sleuth + Zipkin / SkyWalking)
核心作用:给每一次前端请求分配一个全局唯一的追踪 ID,这个 ID 会沿着完整的调用链路在所有服务间传递。每个服务处理请求时,都会记录下自身的处理耗时、异常信息、上下游调用关系。最终所有数据汇聚到可视化平台,输入追踪 ID 就能看到完整的调用链路,快速定位故障节点与性能瓶颈。
总结
原生 Servlet 解决了「Java 能不能处理 Web 请求」的从0到1问题;Spring + Spring MVC 解决了「代码怎么组织更优雅、更易维护」的开发范式问题;Spring Boot 解决了「项目怎么搭最快、部署最简单」的工程效率问题;Spring Cloud 解决了「大规模业务怎么拆分、怎么治理」的架构扩展问题。
更多推荐

所有评论(0)