news 2026/10/16 6:46:12

SpringBoot+SpringCloud微服务脚手架:Nacos注册、Gateway路由与MyBatis实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SpringBoot+SpringCloud微服务脚手架:Nacos注册、Gateway路由与MyBatis实践

简介:面向Java后端开发者的一套微服务架构搭建示例,以Spring Boot为启动框架,整合Spring Cloud分布式组件、Nacos服务注册与配置管理、Spring Cloud Gateway流量网关以及MyBatis持久层,完整呈现从项目初始化到服务间调用、路由转发与数据库交互的落地过程。压缩包共71个文件,以java源码与class字节码为主,辅以xml映射与yml配置,另有sql脚本、jar依赖及工程配置文件,整体仅53KB,便于快速下载查看。已有2419人学习该资源,适合正在学习微服务拆分、服务治理或网关路由的初中级开发者作为参考。通过本资源可了解基于注解与配置文件的工程组织方式,对照Nacos注册中心、Gateway过滤器、Feign远程调用及MyBatis数据访问的具体写法,为自行搭建分布式系统提供可复用的结构模板。

1. 一套能直接落地的微服务脚手架:SpringBoot+SpringCloud+Nacos+Gateway+MyBatis

某公司有个单体应用,代码越堆越重,发版要全员配合,改一行代码得整个服务重启。A同学接手后做的第一件事,就是拿这套 SpringBoot+SpringCloud 微服务组合做拆分试点,Nacos 做注册中心和配置中心,Gateway 做统一入口,MyBatis 继续负责数据访问。两个月下来,服务拆了六个,发布互不干扰,新同事入职第一天就能在本地把整套环境跑起来。这个项目就是那套被反复验证过的脚手架——它不是某个大型商业系统,而是一个把微服务最核心的零件全部组装好、能直接 copy 到业务里改的工程模板。适合正在学微服务、或者准备把单体拆成微服务但对 SpringCloud 全家桶还不太熟的 Java 后端开发者。下文会讲清楚它的架构设计、关键代码、跑通步骤和二次开发的改造路径,照着走,你也能拥有自己的微服务底座。

2. 架构与模块设计:服务怎么互相找到、请求怎么流转

搭建微服务脚手架,最怕一开始就陷进细枝末节。实际落地时,先搞清楚两个问题:每个服务怎么让别人发现自己?外部请求怎么安全地打到正确的服务上?这套项目的答案很干脆:Nacos 负责服务注册与配置管理,Gateway 负责路由转发与统一鉴权,MyBatis 负责数据访问,服务之间用 Feign 走 HTTP 调用。下面把整体设计拆开看。

2.1 技术选型:Nacos、Gateway、MyBatis 为什么能搭在一起

选型阶段其实对比过好几套方案,最后定下这套组合,核心原因是它们各自的定位刚好错开,不重叠也不打架。

服务注册与发现这块,Nacos 比 Eureka 更合适。Eureka 2.x 停更后,很多团队转向 Nacos,它同时提供注册中心和配置中心两个能力,省掉单独搭配置服务器的成本。而且 Nacos 的控制台界面比 Eureka 直观,服务上下线、配置变更都能在页面上看到。关键一点是 Nacos 支持服务端主动推送配置变更,SpringCloud Config 那种靠客户端轮询的模式在时效性上差了一截。

网关选型上,Gateway 替代 Zuul 是主流趋势。Gateway 基于 WebFlux 响应式编程,底层是 Netty,性能和吞吐量比 Zuul 1.x 的 Servlet 模型好不少。而 SpringCloud 官方对 Zuul 的维护也进入停滞状态,新项目基本都默认 Gateway。不过要注意,Gateway 是异步非阻塞模型,里面不能直接用 ThreadLocal 那套同步机制,写过滤器时容易踩坑,这个后面避坑章节会详细说。

持久层用 MyBatis 是因为它半自动化的特性更适合微服务拆分场景。每个服务维护自己的 Mapper XML,SQL 写在 XML 里,改动不需要重新编译 Java 代码;配合 MyBatis-Plus 做单表 CRUD 和分页,多表关联还是自己写 SQL,控制力比 JPA 强。对于从传统 SSM 项目拆过来的团队,MyBatis 的学习成本几乎为零。

组件职责选择理由
Nacos服务注册发现、配置管理双功能合一,控制台可视化,支持配置推送
Gateway统一入口、路由、过滤器响应式非阻塞,性能好,SpringCloud 官方主推
MyBatis/MyBatis-Plus数据持久层SQL 可控,改造成本低,适合复杂查询
OpenFeign服务间声明式调用接口注解方式,与 Ribbon 负载均衡整合

2.2 多模块 Maven 工程结构:每个模块的职责划分

这个项目不是单工程,而是采用多模块 Maven 结构,根目录下按业务域拆成独立 module。这种组织方式的好处是依赖关系清晰,每个服务可以独立打包、独立部署,也能在 IDE 里一键启动多个模块进行本地联调。

microservice-demo/ ├── pom.xml // 父 POM,统一依赖版本管理 ├── common-module // 通用模块:统一返回结果、异常处理、工具类 ├── gateway-server // 网关服务,端口 8080 ├── auth-service // 认证服务,端口 8101,用户登录令牌签发 ├── user-service // 用户服务,端口 8102,用户信息管理 ├── order-service // 订单服务,端口 8103,订单数据操作 └── product-service // 商品服务,端口 8104,商品信息管理

父 POM 里用 dependencyManagement 统一锁定 SpringBoot 和 SpringCloud Alibaba 的版本。这里有个血泪经验:SpringBoot、SpringCloud、SpringCloud Alibaba 三者版本必须严格对应,版本不匹配会出现各种匪夷所思的报错,比如 Nacos 注册不上、Feign 调用失败。项目里用的是 2.6.x 对应的那套版本组合。

common-module 抽取的是所有服务都会用到的东西,包括统一返回结构 Result、全局异常处理器、分页对象。这样业务服务里不用重复写这些样板代码,只依赖 common-module 即可。网关和各业务服务都只关注自己的核心逻辑,公共能力集中在 common 模块。

2.3 请求链路:从外部请求进入网关到数据返回的完整流程

理解微服务架构,最重要的就是脑子里有一条完整的请求链路。这套项目的链路是这样的:

外部客户端发起 HTTP 请求,首先打到 Gateway(网关服务,8080 端口)。Gateway 按路由规则匹配请求路径,比如/api/user/**前缀的请求转发到 user-service,/api/order/**转发到 order-service。转发方式是lb://协议——lb是 load balance 的缩写,Gateway 通过负载均衡器从 Nacos 拉取目标服务的实例列表,再按负载策略挑一个实例发出请求。

请求进入业务服务后,经过 Controller 层调用 Service 层,Service 层通过 MyBatis 的 Mapper 接口操作数据库。如果有跨服务的数据需求,比如订单服务要查用户信息,就通过 OpenFeign 发起一次内部 HTTP 调用,调用目标同样是经过 Nacos 发现的服务实例。

这样一个请求从外部进入到内部完成响应,中间经过了网关路由、负载均衡、服务间调用、数据持久化四层。链路里任何一个环节出问题,请求都会失败,这也是后面排查问题时要按链路逐层看的关键思路。

服务注册与发现是这条链路正常运转的前提。各业务服务启动时,会向 Nacos 注册自己的 IP 和端口;服务调用方从 Nacos 拉取目标服务实例列表,配合 Ribbon 完成负载均衡。如果某个服务挂了,Nacos 会感知到并把它从实例列表里剔除,调用方就不会再往这个挂掉的实例上发请求。

3. 核心代码拆解:Nacos注册、网关路由与数据访问的完整落地

架构设计讲清楚了,代码才是硬通货。这一章挑最核心的四个模块来看它们的实现方式,每一段代码都是在项目里实际能跑通的写法。

3.1 Nacos 服务注册与发现:bootstrap.yml 配置与启动类注解

业务服务接入 Nacos,配置非常简洁,重点在两个文件:pom.xml 里引入依赖,配置文件里声明注册中心和配置中心地址。

<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>

依赖引入后,核心配置写在 bootstrap.yml 里。注意这个文件名,Nacos 配置中心的读取是在 Spring 容器初始化之前,所以必须用 bootstrap.yml 而不是 application.yml 来声明 Nacos 地址,否则配置中心加载不到。

spring: application: name: user-service cloud: nacos: discovery: server-addr: 127.0.0.1:8848 config: server-addr: 127.0.0.1:8848 file-extension: yaml group: DEFAULT_GROUP

逻辑说明:spring.application.name是服务注册到 Nacos 的名称,其他服务调用它时通过这个名称来定位;nacos.discovery.server-addr指定注册中心地址,本地开发一般是 127.0.0.1:8848,部署时改成 Nacos 服务器的实际 IP;nacos.config.file-extension表示从配置中心拉取的配置文件格式是 yaml,默认规则是拉取服务名.yaml这个文件。

参数说明:Nacos 默认端口是 8848,如果 Nacos 部署在别的机器,只需要改server-addr这一个地方。group参数用来做环境隔离,测试环境用 DEFAULT_GROUP,生产环境可以改成 PROD_GROUP,防止配置互相覆盖。

启动类上的注解也别忘了。业务服务的主类上加上@SpringBootApplication和@EnableDiscoveryClient注解,后者是 SpringCloud 标准注解,作用是开启服务注册发现功能。

@SpringBootApplication @EnableDiscoveryClient public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }

这段代码里,@EnableDiscoveryClient不是必须加的——SpringCloud 新版中引入 Nacos 依赖后会自动开启注册。但建议显式加上,一是语义更清晰,二是团队里有人如果用了旧版依赖,不加这个注解会导致服务注册不上,排查起来费劲。

启动服务后,打开 Nacos 控制台(默认地址 127.0.0.1:8848/nacos),在服务管理页面能看到 user-service 已经出现在服务列表里,这就是注册成功的标志。

3.2 Gateway 网关:路由规则、过滤器与跨域配置

网关是流量的枢纽,配置质量直接决定整套系统能不能正常对外服务。看一下它的核心配置和过滤器的实现。

server: port: 8080 spring: application: name: gateway-server cloud: nacos: discovery: server-addr: 127.0.0.1:8848 config: server-addr: 127.0.0.1:8848 file-extension: yaml gateway: routes: - id: user-route uri: lb://user-service predicates: - Path=/api/user/** filters: - StripPrefix=1 - id: order-route uri: lb://order-service predicates: - Path=/api/order/** filters: - StripPrefix=1 - id: product-route uri: lb://product-service predicates: - Path=/api/product/** filters: - StripPrefix=1

路由配置的逻辑说明:每条路由由 id、uri、predicates、filters 四部分组成。predicates是路由匹配条件,这里用的是 Path 方式,/api/user/**表示所有以/api/user/开头的请求都命中这条路由;uri是转发目标,lb://表示从 Nacos 拉取服务实例,user-service 就是注册到 Nacos 的服务名;StripPrefix=1是过滤器,含义是转发时去掉路径的第一段,比如请求/api/user/info转发到 user-service 时,实际路径变成/info。

参数说明:StripPrefix 的数字要看实际需求。如果 Gateway 对外路径和业务服务内部路径不同,比如对外统一加/api前缀,则必须用 StripPrefix 去掉;如果一致,就不需要这个过滤器。这里使用/api作为统一前缀,所以每个路由都配了 StripPrefix=1。

如果项目里存在跨域需求——比如前端页面跑在 8081 端口,接口在 8080 端口——Gateway 层要统一配置跨域,不放在各业务服务配置,否则每个服务还得单独加 CORS 配置,容易漏。

@Configuration public class CorsConfig { @Bean public CorsWebFilter corsWebFilter() { CorsConfiguration config = new CorsConfiguration(); config.addAllowedMethod("*"); config.addAllowedOriginPattern("*"); config.addAllowedHeader("*"); config.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source); } }

跨域逻辑说明:这个配置针对所有路径开放跨域,addAllowedMethod("*")允许 GET、POST、PUT、DELETE 等所有请求方式;addAllowedOriginPattern("*")允许所有来源访问,注意必须用 OriginPattern 而不能用加*的 addAllowedOrigin,因为后者在setAllowCredentials(true)开启时会被浏览器拒绝。

3.3 MyBatis 数据访问层:Mapper 接口、XML 与分页插件

业务服务的数据访问用的是 MyBatis-Plus,它在 MyBatis 基础上封装了通用 CRUD,单表操作不需要写 SQL。

@Mapper public interface UserMapper extends BaseMapper<User> { // 继承 BaseMapper 后自带 insert/update/selectById/delete 等单表方法 // 自定义分页查询:按状态筛选用户列表 IPage<User> selectUserPage(Page<User> page, @Param("status") Integer status); }
<select id="selectUserPage" resultType="com.demo.modules.user.entity.User"> SELECT id, username, mobile, status, create_time FROM user WHERE status = #{status} ORDER BY create_time DESC </select>

逻辑说明:BaseMapper是 MyBatis-Plus 提供的通用 Mapper 父接口,泛型参数是实体类 User,它内置了十几二十个单表方法,基本上增删改查不用自己写 SQL。selectUserPage是自定义方法,与 XML 里 id 对应的方法名绑定,MyBatis 通过动态代理生成实现。

参数说明:Page对象是 MyBatis-Plus 的分页参数,构造时传入当前页和页大小,比如new Page<>(1, 10)表示查第一页,每页 10 条。分页在底层通过拦截器把 limit 拼进 SQL,所以在配置类里需要注册分页插件,否则分页不生效。

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }

分页插件的逻辑说明:PaginationInnerInterceptor是物理分页拦截器,它会在执行 SQL 前自动拼接 limit 语句。DbType.MYSQL指定数据库类型,如果换用 PostgreSQL,这里要改成DbType.POSTGRE_SQL。注册了这个 Bean,前面selectUserPage方法里传入的Page参数才能生效,且分页结果会回填到Page对象里,通过page.getRecords()取出当前页数据、page.getTotal()取出总条数。

3.4 服务间调用:OpenFeign 声明式接口与熔断降级

微服务之间跨服务调用时,用 OpenFeign 是最省事的方式。在订单服务里要查用户信息,定义一个 Feign 接口即可。

@FeignClient(name = "user-service", fallbackFactory = UserClientFallbackFactory.class) public interface UserClient { @GetMapping("/user/info/{id}") Result<UserInfo> getUserInfo(@PathVariable("id") Long id); }

逻辑说明:@FeignClient声明这是一个远程调用客户端,name属性填目标服务在 Nacos 注册的名称 user-service,Feign 会根据这个名称去 Nacos 拉取实例并发起请求。接口方法上的@GetMapping("/user/info/{id}")指定了调用 user-service 的具体路径和 HTTP 方法。调用方就像调用本地接口一样调用userClient.getUserInfo(id),底层实际是生成了一个 HTTP 请求发到 user-service 上。

参数说明:fallbackFactory是服务降级的配置,指定一个回退工厂类。当 user-service 不可用或响应超时时,Feign 不会抛异常,而是调用 fallback 里的方法返回一个兜底结果。生产环境建议每个 Feign 接口都配 fallback,避免一个服务挂掉导致调用方跟着崩溃。

@Component public class UserClientFallbackFactory implements FallbackFactory<UserClient> { @Override public UserClient create(Throwable cause) { return new UserClient() { @Override public Result<UserInfo> getUserInfo(Long id) { return Result.fail("用户服务暂时不可用"); } }; } }

降级逻辑说明:当远程调用失败时,Feign 会进入这个工厂的 create 方法,返回一个临时的 UserClient 匿名实现类,调用方拿到的是降级后的结果而不是异常。这样即使下游服务挂了,上游服务也能正常返回响应,只是数据为空或提示错误,不会出现雪崩。超时时间可以在配置文件里调,feign.client.config.default.connect-timeout和read-timeout分别控制连接超时和读取超时。

服务间调用的链路到这里就打通了:Gateway 转发请求到订单服务,订单服务通过 Feign 调用用户服务,用户服务通过 MyBatis 查数据库,结果再逐层返回。整个链路各司其职,每个环节都不越界。

4. 本地跑通:从零启动五个节点的验证路径

代码看完了,关键是能跑起来。这一章按实际启动顺序走一遍,每一步都有验证方法,跟着做就行。整套环境需要五个进程:Nacos、四个服务(网关、用户、订单、商品),本地开发时数据库用 MySQL 即可。

4.1 环境准备:版本选择与安装要点

先把环境基础打好。JDK 建议用 1.8 或 11——SpringBoot 2.6.x 在这两个版本下最稳定,太高或太低都可能出现兼容问题。Maven 用 3.6 以上版本,配置好阿里云镜像,不然拉 SpringCloud Alibaba 的依赖会非常慢。MySQL 用 5.7 或 8.0 都行,各服务库表结构由 MyBatis 对应的 SQL 脚本初始化。

Nacos 的启动方式:下载 2.x 版本解压后,Linux 或 Mac 执行sh startup.sh -m standalone,Windows 执行cmd startup.cmd -m standalone。-m standalone参数表示单机模式启动,本地开发不需要集群。启动后访问http://127.0.0.1:8848/nacos,账号密码默认都是 nacos,能看到控制台页面就成功了。

提示:本地 MySQL 创建三个数据库 user_db、order_db、product_db,分别给三个业务服务用。微服务拆分后每个服务独立数据库,这是规范做法,避免所有服务共用一个库,否则拆分的意义就没了。

4.2 依赖配置检查:确认关键版本对应关系

很多跑不起来的问题都出在版本不匹配上。项目里各个模块的版本依赖是经过验证的,可以用以下表格自查:

组件版本说明
SpringBoot2.6.8不要用 3.x,SpringCloud 对应关系不同
SpringCloud2021.0.3与 SpringBoot 2.6.x 匹配
SpringCloud Alibaba2021.0.4.0与 SpringCloud 2021.0.3 匹配
Nacos Server2.1.0与服务端版本无关,客户端兼容
MyBatis-Plus3.5.2支持 SpringBoot 2.x

如果版本对不上,最常见的结果是 Nacos 注册不上、Feign 调用报 ClassNotFoundException 这类诡异错误。项目里所有依赖版本统一在父 POM 的 dependencyManagement 里声明,子模块不加版本号,防止各处版本漂移。

4.3 按顺序启动服务并逐项验证

启动顺序是:先 Nacos,再业务服务,最后网关。业务服务内部没严格顺序,因为 Nacos 注册是异步的,谁先起来都能被发现。

第一步,启动 Nacos,确认控制台可访问。第二步,启动 user-service。启动成功的标志:控制台日志出现Registered service with nacos, service: user-service字样。到 Nacos 控制台的服务列表页面,能看到 user-service 的状态为 UP。

第三步,依次启动 order-service 和 product-service,同样在控制台确认注册成功。第四步,启动 gateway-server,控制台日志同样会打印注册信息。

此时开始验证链路。先验证网关路由是否生效,从外部访问用户服务接口:

curl http://127.0.0.1:8080/api/user/info/1

如果响应 JSON 数据,说明链路已通。这条请求的完整路径是:curl 打到 Gateway 的 8080 端口,Gateway 按 Path 规则匹配到user-route,通过 lb 负载均衡转发到 user-service 实例,user-service 的 Controller 接收请求后返回用户数据,再原路返回。

再验证服务间调用,订单服务里如果有一个接口需要远程查用户信息,访问订单接口时会触发 Feign 调用。观察 order-service 的日志,能看到它向 user-service 发起了内部 HTTP 请求。如果在 user-service 里打断点,也能看到来自 order-service 的调用线程。

最后验证 Nacos 配置中心。在 Nacos 控制台新建配置文件user-service.yaml,填写test-key: dev-config,然后在 user-service 的代码里用@Value("${test-key:default}")读取这个配置,重启服务或调用配置刷新接口,确认值从配置中心拉取成功。

4.4 验证完成之后的收尾确认

整套跑通后,最后一步是在 Nacos 控制台的服务列表里核对所有服务都已注册、状态都是 UP。如果有服务没注册上,按这个顺序排查:确认 Nacos 配置中心的服务地址写对了没有,确认 bootstrap.yml 放在 src/main/resources 目录下,确认 pom.xml 里引入了 nacos-discovery 依赖。

另外推荐关闭防火墙或放行 8848、8080 等端口。很多本地联调失败不是代码问题,而是端口被防火墙挡了,服务之间网络不通。开发机上先临时关掉防火墙,跑通后再按需配置安全组规则。

5. 避坑指南:微服务搭建里的五个真实翻车现场

这套项目在落地过程中踩过不少坑,每一条都是花时间排查过的,写出来供各位参考。都是实际的踩坑记录,现象、原因、解决一条条捋清楚。

5.1 Nacos 连接超时,服务注册不上去

现象:启动业务服务时,控制台持续打印nacos registry register failed或Connection refused,等一会儿服务还是不在 Nacos 服务列表里。

原因:大多数情况下是 bootstrap.yml 里 Nacos 地址写错或没生效。第二个常见原因是配置文件命名问题——如果文件叫 application.yml,Nacos 配置中心的连接配置不会加载,因为配置中心的客户端在 Spring 上下文初始化前就要工作,必须走 bootstrap 上下文。

解决:确认文件确实叫 bootstrap.yml(不要拼成 bootstrap.yaml),确认 server-addr 的 IP 和端口可访问。本地用 start.sh 启动的 Nacos 默认监听 8848,注意如果是服务器部署,防火墙别把 8848 端口禁止了。用telnet 127.0.0.1 8848测一下连通性最快。

5.2 Gateway 路由转发到实际服务时报 503 错误

现象:请求网关接口时返回 503 Service Unavailable,网关日志显示Unable to find instance for user-service。

原因:问题在注册中心和网关的配合环节。Gateway 通过 lb://user-service 去 Nacos 拉取实例,如果 user-service 没有成功注册,或者注册后还没有被 Gateway 的负载均衡器感知到,就会报这个错。还有一个常见原因是 user-service 注册到 Nacos 时状态异常,比如健康检查失败被标记为 DOWN。

解决:先在 Nacos 控制台看 user-service 是否存在且状态为 UP。如果控制台显示 DOWN,去 user-service 日志里查健康检查失败原因,常见的是数据库连接池初始化失败或 Redis 连接不上。等日志清楚后重启服务。如果服务状态正常但网关依然 503,等待 5-10 秒让实例列表刷新,然后重试。

5.3 MyBatis Mapper 接口扫描不到,启动报错

现象:服务无法启动,报Invalid bound statement (not found)或Property 'mapperLocations' was not specified。

原因:Mapper 接口和 XML 文件的扫描路径配置不一致。如果 Mapper 接口加了@Mapper注解,但 XML 文件放在 resources 下的另一个包路径,MyBatis 就找不到绑定关系。还有一种情况是接口没加@Mapper注解,主类上也没配@MapperScan,接口根本没有被扫描进 Spring 容器。

解决:两种方式任选其一——在主类上加@MapperScan("com.demo.modules.user.mapper"),或者在每个 Mapper 接口上单独加@Mapper注解。同时检查 XML 文件的路径是否与接口的包路径一致,项目里把 XML 放在 resources/mapper 目录下,在 application.yml 里配置mybatis-plus.mapper-locations: classpath*:mapper/**/*.xml。

5.4 服务间用 Feign 调用,启动时直接报循环依赖

现象:项目启动报错,提示The dependencies of some of the beans in the application context form a cycle。

原因:微服务拆分初期很常见,比如 A 服务调用 B,B 服务又回调 A,两边互相声明了 FeignClient,形成了循环依赖。Spring 的构造器注入对循环依赖是不支持的,直接启动失败。

解决:治理方向有两个——重新审视服务边界,把循环调用的逻辑抽到更细的服务或下沉到独立的模块,让依赖变成单向的;如果短时间不好拆,可以在配置里开启允许循环依赖,spring.main.allow-circular-references: true。但这个只是权宜之计,治标不治本,后续还是要解决调用链方向问题。

5.5 SpringBoot 2.6.x 网关启动报 RoutePredicateFactory 不识别

现象:网关启动时日志提示某种 Predicate 工厂类找不到或无法解析,比如 Path 断言不生效。

原因:SpringCloud Gateway 与 SpringBoot 版本不匹配,常见于远程仓库拉取依赖时因为镜像源不同导致版本串了。SpringBoot 2.6.x 里对循环引用默认关闭,而对 Gateway 的某些自动配置也做了调整,导致旧版 Gateway 路由配置解析异常。

解决:确认 SpringCloud 版本必须是 2021.0.x,且与 SpringBoot 2.6.x 配套;如果是从网上找的零散依赖版本,统一改到父 POM 里管理,让 maven 依赖树里只有一个版本的 SpringCloud。执行mvn dependency:tree排查是否有多个不同版本的 gateway 依赖,把多的排除掉。

这些坑都是真实环境里出现过的问题,每遇到一个,排查的思路都是类似的:先看配置是否生效,再看服务是否注册,最后看依赖版本是否一致。微服务排障没有黑匣子玄学,链路里的每一环都有日志可以查,按链路逐步定位就能找到根因。

6. 二次开发:新增一个微服务并接入网关的改造路径

最后这部分聊改造。把这套脚手架当成模板,你大概率不是直接拿它上线,而是要往里加自己的业务。最大的改造场景就是新增一个微服务模块,完整路径一般是五步。

第一步,复制一个现有业务服务的目录结构,改模块名和包名。比如现在要加一个库存服务 stock-service,把 order-service 的目录复制过来,全局替换 order 为 stock、Order 为 Stock。第二步,在父 POM 的 modules 标签里加上 stock-service 模块声明,同时子模块的 pom.xml 里把 common-module 依赖加上。第三步,配置 bootstrap.yml,application.name 改成 stock-service,端口改成独立端口。第四步,写自己的实体类、Mapper、Service、Controller,数据源指向新的数据库。第五步,在 Gateway 的 routes 配置里加一条新路由。

- id: stock-route uri: lb://stock-service predicates: - Path=/api/stock/** filters: - StripPrefix=1

路由配置的身份说明:Gateway 配置改完后,外部请求/api/stock/**就能自动路由到新的库存服务。前提是 stock-service 已经成功注册到 Nacos,这一步可以通过控制台服务列表确认。不需要重启网关——如果配置在 Nacos 配置中心里,动态刷新后路由规则会更新,但本地开发阶段建议直接重启网关,简单可靠。

依赖方向的设计:新增服务独立运作,唯一需要关心的依赖关系就是它的数据源和对外暴露的接口。保持单向调用是一种好的设计习惯——比如库存服务可以被订单服务调用,但库存服务不应该再去调用订单服务,这样依赖树始终是清晰的分层结构。

还有一个二次开发常用的点是网关层做灰度发布。Nacos 本身支持临时调整服务权重,把某个新版本服务的权重调低、旧版本调高,就能实现金丝雀发布的小规模验证。操作上在 Nacos 控制台的实例详情里修改权重,或者通过 API 方式修改,这在没有引入完整灰度平台时是最轻量的方式。

做这套项目改造时,我养成的一个习惯是:每次新增服务或改动路由,都强制走一遍同一个验证流程——先看 Nacos 控制台服务列表确认服务注册成功,再 curl 网关的对外接口确认路由生效,最后看业务服务日志确认调用链路完整。这样改完三次之后,问题基本都能在第一时间定位到具体环节。

那段时间的教训是:微服务这玩意一旦拆开,排错成本比单体高一个量级,全靠事前把接口边界、配置规范、链路验证这三件事做扎实。现在团队里新同学不管是在这套脚手架上加服务,还是改路由、调降级策略,都用这套流程走一遍,翻车概率低了很多。这套东西帮团队减少了大量联调返工,希望帮到你。

提示:二次开发上线前,把 Gateway 层、Nacos 配置中心和数据库连接串这三样东西做一个固定顺序的自检清单。微服务架构的稳定性不全靠代码,靠的是每次变更都把它当发布对待的习惯。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 6:46:09

Teigha SDK入门:轻量级DWG/DXF解析实战指南

简介&#xff1a;本资源是面向CAD二次开发工程师与.NET平台开发者的Teigha 4.0基础应用实战项目&#xff0c;聚焦DWG文件的读取、新建及后台批量文字替换三大核心场景&#xff0c;解决工业设计、图纸自动化处理等实际工程中常见的非交互式CAD数据操作需求。压缩包共63个文件&am…

作者头像 李华
网站建设 2026/10/16 6:45:37

OmniPeek 7 深度解析:协议级网络诊断与自动化合规实践

简介&#xff1a;本资源为WildPackets公司出品的专业级网络协议分析工具OmniPeek 7.0完整安装包&#xff0c;面向网络管理员、安全工程师及具备TCP/IP基础的IT技术人员&#xff0c;用于深度数据包捕获、实时流量监控、性能瓶颈定位与网络安全事件溯源。压缩包共105个文件&#…

作者头像 李华
网站建设 2026/10/16 6:45:34

搞定千万级CSV导出:Java流式方案,告别内存溢出

简介&#xff1a;针对Java后端处理千万级CSV导出的常见痛点&#xff0c;这份资源提供了一套完整的多线程分批导出实现方案&#xff0c;适合有Java基础、正在应对大数据量报表导出或日志导出场景的开发者参考。资源压缩包共10个文件&#xff0c;以9个Java源码为主&#xff0c;覆…

作者头像 李华
网站建设 2026/10/16 6:42:33

Genesis97在Win10上的安装全攻略:兼容性配置与排错实战

简介&#xff1a;这是一个面向PCB设计与制造从业者的Genesis软件安装包&#xff0c;适用于Windows 10 64位系统&#xff0c;重点解决安装过程易中断、完成后报内部错误等常见问题。压缩包共952个文件&#xff0c;约183.66MB&#xff0c;包含主安装程序exe、PCB工程数据pcz、脚本…

作者头像 李华
网站建设 2026/10/16 6:41:41

CSV和JSON怎么互转?用华为云码道快速开发数据格式转换工具

CSV和JSON怎么互转&#xff1f;用华为云码道快速开发数据格式转换工具 华为云码道CodeArts代码智能体_下载安装_免费体验-华为云 Security Verification 深圳技术大学 - 开源代码托管,代码协作 - AtomGit csv-json-converter:一个基于HTML、CSS和JavaScript实现的CSV与JSON…

作者头像 李华