SpringBoot+SpringCloud+Nacos微服务骨架搭建:版本选型与避坑指南
简介这是一份围绕 Spring Boot、Spring Cloud、Nacos、Gateway 与 MyBatis 五大组件搭建完整微服务架构的实战资源定位为 Java 开发者学习分布式系统的入门到进阶参考资料。资源以可运行示例工程演示服务注册发现、统一网关路由、配置中心管理及数据库持久化等核心环节项目按模块拆分便于理解微服务之间的协作方式与分层边界。压缩包共 71 个文件以 java 源码、class 编译产物、xml 映射与配置、yml 配置清单为主体附带 sql 初始化脚本、jar 依赖及 properties 配置文件整体仅 53KB结构轻量、便于本地直接导入复现。目录按 user-service、gateway、product-service、feign-api 等模块组织从网关入口到业务服务再到数据访问均有对应实现适合对照学习微服务拆分粒度与模块间调用关系。已有 2419 人学习下载。对准备入职或正在做毕设的 Java 开发者而言这份资源可直接作为脚手架模板结合源码理解各组件在真实项目中的职责边界节省从零搭建环境与排查整合问题的时间也能为后续扩展分布式组件提供可对照的起点。1. 微服务套件装进本地版本矩阵才是最大的坑一套 SpringBoot SpringCloud Nacos Gateway MyBatis 的微服务骨架是整个 Java 后端最常见的落地方案几乎每个公司都要搭一遍。但真正动手时你会发现代码写得再漂亮也扛不住 SpringBoot 和 SpringCloud 版本对不上——启动三秒就报错报错信息还全是 Bean 找不到、依赖循环这类看不懂的黑话翻半天文档才发现是版本矩阵选错了。这不是个例我接手过好几个项目翻车都是同一个原因要么 SpringBoot 升到了 2.7 却配了 Hoxton 的 Cloud要么 Nacos 用了 2.x 但没开 9848 端口要么 Gateway 模块里手滑引了 web 包导致端口冲突。这套环境的复杂度不在业务代码里而在版本对应关系和注册中心的启动配置上。这篇文章把版本选型、Nacos 安装、父工程搭建、Gateway 路由配置、MyBatis 接入和验证链路从头走一遍适合正在搭第一批微服务模块的开发者也适合被版本问题卡住想换一套稳妥组合的人。2. 先把底座备齐JDK、Maven 与 Nacos 的环境选型和启动2.1 JDK 与 Maven 版本选型先定坐标再写代码搭建微服务环境的第一步不是打开 IDE 写代码而是先把 JDK、Maven 和 Nacos 的版本定死。微服务的基础环境一旦版本不匹配后续所有服务都会受影响尤其是 SpringBoot 与 SpringCloud 的版本依赖关系必须先确定组合再动工。推荐一套经过验证的稳定组合JDK 1.8、Maven 3.6.3、SpringBoot 2.3.12.RELEASE、SpringCloud Hoxton.SR12、SpringCloud Alibaba 2.2.5.RELEASE、Nacos 2.2.3。JDK 1.8 依旧是微服务项目的主流选择虽然更高版本的 JDK 也能跑但很多公司的存量依赖和 MyBatis 插件对 JDK 8 的支持最稳定不必在基础环境上冒险。Maven 安装完成后需要检查镜像源配置国内网络环境下建议在settings.xml中配置阿里云镜像否则下载 SpringCloud Alibaba 依赖时会非常慢甚至超时失败。mirror idaliyunmaven/id mirrorOf*/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror这段配置写在 Maven 安装目录conf/settings.xml的mirrors节点内。mirrorOf设为*表示所有仓库请求都走阿里云镜像url指向阿里云公共仓库它聚合了 Maven Central 和 JCenter 的制品。配置完成后用mvn -v验证 Maven 版本号是否正常输出再用一个空项目执行mvn dependency:resolve测试依赖下载是否顺畅。2.2 下载并启动 Nacos单机模式下的两个启动参数Nacos 在这里同时承担注册中心和配置中心两个角色是整套微服务体系最先启动的组件。去 Nacos 官方 GitHub Releases 页面下载nacos-server-2.2.3.tar.gz解压后进入bin目录Linux 环境直接执行启动脚本# Linux / macOS 单机模式启动注意是 startup 不是 start sh startup.sh -m standalone # Windows 环境用 startup.cmd -m standalone-m standalone参数指定单机模式启动。Nacos 默认以集群模式读取配置不加这个参数会一直尝试寻找集群节点并反复报错。启动完成后观察日志出现Nacos started successfully就代表启动成功。Nacos 2.x 版本启动后默认监听 8848 端口提供控制台和 HTTP API但同时还会监听 9848 端口用于 gRPC 通信这是 2.x 与 1.x 的核心差异之一。如果服务器有防火墙或运行在云主机上只放行 8848 会导致客户端连接超时需要同时放行 8848 和 9848。启动后访问http://localhost:8848/nacos默认账号密码都是nacos登录后能看到服务列表、配置列表等管理界面。这个控制台在后面排查服务注册问题时非常有用服务是否上线、配置是否加载成功都一目了然。2.3 验证 Nacos 控制台确认注册中心与配置中心就绪Nacos 启动后不要急着开始写工程代码先做两个快速验证确认底座是好的。第一个验证是打开控制台页面确认登录成功且左侧菜单完整第二个验证是确认 9848 端口在监听执行netstat -an | grep 9848如果只看到 8848 而看不到 9848说明 Nacos 2.x 的 gRPC 端口未正常监听需要检查是否为端口冲突。这两个验证都通过后注册中心和配置中心才算真正就绪后续任何服务注册不上、配置拉不到的问题都可以优先怀疑依赖配置而不是 Nacos 本身。3. 搭建父工程与公共模块用一套坐标锁死所有版本3.1 父工程 pomdependencyManagement 统一锁定关键坐标微服务项目通常采用多模块结构父工程只做依赖版本管理不写业务代码。在父 pom 中通过dependencyManagement锁定 SpringBoot、SpringCloud、SpringCloud Alibaba 三大组件的版本子模块引入依赖时就不必再写版本号这能从根本上避免多个服务版本不一致的问题。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.3.12.RELEASE/version relativePath/ /parent properties spring-cloud.versionHoxton.SR12/spring-cloud.version spring-cloud-alibaba.version2.2.5.RELEASE/spring-cloud-alibaba.version mybatis-starter.version2.1.4/mybatis-starter.version /properties dependencyManagement dependencies dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version${spring-cloud.version}/version typepom/type scopeimport/scope /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-dependencies/artifactId version${spring-cloud-alibaba.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement这段配置的核心是import方式的依赖管理。SpringCloud 和 SpringCloud Alibaba 都发布了统一的 BOMBill of Materials包通过scopeimport/scope引入后相当于把这两个体系管理的所有组件版本都纳入了当前工程的版本约束范围。注意 SpringCloud Alibaba 2.2.5.RELEASE 对应的是 Nacos 1.4.x 客户端但服务端用 2.2.3 依然兼容良好这是社区验证过最广泛使用的组合。父 pom 的packaging要设置为pom否则构建时会报类型错误。子模块的parent指向这个父工程后只需声明groupId和artifactId版本号自动沿用父工程的定义。3.2 公共 API 模块把实体类和 Feign 接口单独抽一层公共模块common-api的职责是存放各服务共享的实体类、统一返回体和 Feign 调用接口。这个模块不启动任何服务只提供依赖引用。抽取公共模块有几个实际好处实体类统一管理避免多个服务重复定义、Feign 接口与实现分离让服务间调用解耦、序列化字段不一致导致的数据错乱从源头消除。artifactIdcommon-api/artifactId dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId optionaltrue/optional /dependency /dependenciesoptionaltrue/optional表示这个 web 依赖不会被传递到引用方因为 common-api 被业务服务引用时业务服务自身已经带了 web 或 webflux 依赖避免重复引入造成冲突。在 common-api 中定义统一返回体ResultT包含code、message、data三个字段提供success()和error()静态工厂方法所有微服务接口都返回这个结构前端解析逻辑统一排查问题也方便。3.3 在 Nacos 里预建配置文件dataId 规则与数据库配置把配置放在 Nacos 而不是本地application.yml中是微服务配置中心的核心价值。Nacos 的配置管理遵循dataId规则格式为${spring.application.name}-${profile}.${file-extension}例如user-service-dev.yaml。服务启动时会根据应用名和激活的 profile 自动拉取对应配置。在 Nacos 控制台的配置列表页面新增一条配置dataId填user-service-dev.yamlgroup保持DEFAULT_GROUP配置内容为spring: datasource: url: jdbc:mysql://localhost:3306/micro_user?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.demo.common.entityserverTimezoneAsia/Shanghai是连接 MySQL 8 的必备参数不设置会报时区错误。mapper-locations指定 XML 文件位置type-aliases-package让 MyBatis 能直接使用实体类短类名作为参数和返回值类型避免在 XML 中写全限定类名。这里把数据库和 MyBatis 配置放在 Nacos 中管理环境切换时只需在 Nacos 上调整配置而无需重新打包。4. 避坑手册微服务启动阶段最容易翻车的几个点4.1 SpringBoot 与 SpringCloud 版本错配导致 Bean 找不到现象项目启动时抛出IllegalStateException或BeanCreationException日志提示找不到某个自动配置类比如GatewayAutoConfiguration或NacosDiscoveryAutoConfiguration控制台没有具体原因业务代码一行没写也会启动失败。原因SpringBoot 和 SpringCloud 版本没有按官方对应关系搭配。SpringBoot 2.3.x 对应 SpringCloud HoxtonSpringBoot 2.4 开始对应 2020.0.x 新版本号体系。如果 SpringBoot 用了 2.7 而 Cloud 还停留在 Hoxton由于内部 API 变更大量自动配置类无法装配。解决最稳妥的做法是强制固定版本组合。SpringBoot 2.3.x 配 Hoxton.SR12SpringBoot 2.4.x 到 2.7.x 配 2021.0.x。我在搭建环境时会把版本组合写进父 pom 的properties中并加注释说明防止后续维护者升级时把组合改乱。4.2 Nacos 2.x 客户端连接超时除了 8848 还有 9848现象服务启动日志显示 Nacos 注册中心连接成功但实际服务列表始终为空或者注册请求反复重试报Client not connected, current status: STARTING的错误。控制台能打开但客户端连不上。原因Nacos 2.x 引入了 gRPC 通信客户端注册、心跳、配置推送都走 9848 端口只有 HTTP API 走 8848。很多环境只放行了 8848服务端日志没有报错但客户端连接一直卡在握手阶段表现就是“注册好像成功了但列表里根本没有”。解决服务器安全组或防火墙同时放开 8848 和 9848并确认 9848 端口未被占用。本地开发环境如果是修改过 Nacos 默认端口的还要在客户端配置里同步修改spring.cloud.nacos.discovery.port对应的 gRPC 偏移量。4.3 Gateway 模块误引 spring-boot-starter-web 导致启动冲突现象Gateway 服务启动时出现Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway的报错或者网关启动成功后所有路由都不生效访问 API 直接 404。原因Gateway 基于 Spring WebFlux 实现而spring-boot-starter-web引入的是 Spring MVC。两者同时存在于 classpath 时容器初始化会冲突Gateway 的自动配置被跳过或覆盖。解决Gateway 模块不要引入spring-boot-starter-web或spring-boot-starter-webmvc只用spring-cloud-starter-gateway。如果网关模块需要调用其他服务接口用 WebClient 而不是 RestTemplate。4.4 MyBatis 扫不到 Mapper 接口MapperScan 位置放错现象Mapper 接口和 XML 文件都写好了运行时报Invalid bound statement (not found)代码编译正常但 MyBatis 找不到对应的 SQL。原因MapperScan注解扫描的包路径不对或者没有加这个注解。MyBatis 的 XML 文件路径与接口全限定名不对应时也会出现同样的异常。解决启动类上使用MapperScan(com.demo.user.mapper)明确指定 Mapper 接口所在的包。同时保证 XML 文件在resources/mapper/目录下且 XML 的namespace必须与接口全限定名保持一致。如果用了 Nacos 管理 MyBatis 配置还要确认mybatis.mapper-locations配置确实被加载了。4.5 Feign 调用报 LoadBalancer 找不到Ribbon 已被移除现象服务引入 OpenFeign 后编译通过但运行时报java.lang.IllegalStateException: No Feign Client for loadBalancing defined或LoadBalancerClient not found。原因SpringCloud 2020 版本起 Ribbon 被移除OpenFeign 需要显式引入spring-cloud-starter-loadbalancer才能获得负载均衡能力。旧教程大多只加 OpenFeign 依赖导致新版本无法初始化。解决在调用方服务的 pom 中同时引入 OpenFeign 和 LoadBalancer 两个依赖。Hoxton 版本则不需要额外引入。这个坑在版本升级时极为常见凡是 OpenFeign 调用失败先检查依赖导入是否完整。5. 业务服务与网关落地从注册到路由再到数据库查询5.1 搭建 user-service注册中心、配置中心和 MyBatis 三合一接入user-service是第一个业务服务承担用户信息的增删改查最能体现微服务模块的完整配置。它的 pom 需要集成 Nacos 注册、Nacos 配置、MyBatis、MySQL 驱动、common-api、OpenFeign 和负载均衡组件。dependencies dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-config/artifactId /dependency dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version${mybatis-starter.version}/version /dependency dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-openfeign/artifactId /dependency dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-loadbalancer/artifactId /dependency /dependenciesnacos-discovery负责服务注册与发现nacos-config负责拉取远程配置两个依赖必须同时存在才构成完整的配置中心能力。mysql-connector-java只在运行时需要所以scope设为runtime。OpenFeign 和 LoadBalancer 之所以成对出现是因为服务间调用需要知道目标服务地址由 Nacos 提供实例列表后再由 LoadBalancer 做负载均衡选择。user-service 的application.yml是整个配置的核心spring: application: name: user-service profiles: active: dev cloud: nacos: discovery: server-addr: 127.0.0.1:8848 config: server-addr: 127.0.0.1:8848 file-extension: yaml namespace: publicspring.application.name必须与 Nacos 配置中心的dataId前缀保持一致这是服务注册后显示在控制台的服务名。profiles.active指定当前环境为 dev配合 Nacos 上配置的user-service-dev.yaml完成拼接。file-extension设置为yaml表示配置格式。namespace默认是public如果一开始不做多环境隔离用它即可不需要额外创建命名空间。启动类上需要同时加EnableDiscoveryClient和MapperScanSpringBootApplication EnableDiscoveryClient MapperScan(com.demo.user.mapper) public class UserServiceApplication { public static void main(String[] args) { SpringApplication.run(UserServiceApplication.class, args); } }EnableDiscoveryClient在 SpringCloud Edgware 之后版本其实可以省略但保留它能更直观地表达“这是一个注册到 Nacos 的服务”。MapperScan是 MyBatis 的 Mapper 扫描注解扫描到接口后自动生成代理实现类。启动日志出现Registering service with nacos表示注册成功。5.2 UserMapper 与 XMLMyBatis 从配置到可用的完整闭环Mapper 接口定义标准的 CRUD 方法XML 文件编写具体 SQL这是 MyBatis 最经典的配置方式public interface UserMapper { User findById(Param(id) Long id); }?xml version1.0 encodingUTF-8? !DOCTYPE mapper PUBLIC -//mybatis.org//DTD Mapper 3.0//EN http://mybatis.org/dtd/mybatis-3-mapper.dtd mapper namespacecom.demo.user.mapper.UserMapper select idfindById resultTypecom.demo.common.entity.User SELECT * FROM t_user WHERE id #{id} /select /mapper需要注意的是XML文件必须放在src/main/resources/mapper/目录下并在 Nacos 配置上配好mybatis.mapper-locations: classpath:mapper/*.xml这个配置会被nacos-config拉取并应用到 MyBatis 的 SqlSessionFactory 构建过程。如果改来改去还是报Invalid bound statement先看 target 目录里有没有把 XML 打包进去很多所谓“改了一百遍还是不行”的问题其实是构建目录下还是旧文件。5.3 Gateway 网关模块路由转发是核心诉求Gateway 是外部请求进入微服务集群的大门配置一个可用的网关模块只需要做两件事注册到 Nacos 以便发现下游服务地址配置路由规则把请求转发给对应的服务。在网关的application.yml中spring: application: name: gateway-server cloud: nacos: discovery: server-addr: 127.0.0.1:8848 gateway: routes: - id: user-route uri: lb://user-service predicates: - Path/api/user/** filters: - StripPrefix1 - id: order-route uri: lb://order-service predicates: - Path/api/order/** filters: - StripPrefix1 server: port: 8080路由配置的uri使用lb://前缀表示通过 Nacos 发现服务实例并做负载均衡转发这是网关与硬编码地址方式的本质区别。Predicates定义路由匹配条件Path/api/user/**表示匹配所有/api/user/开头的请求。StripPrefix1是个容易被忽视的过滤器它把路径中的第一个前缀去掉即真实的/api/user/1到达 user-service 时会被转为/1因为请求路径中的api和user都是网关层的前缀服务内部不需要。启动网关后访问http://localhost:8080/api/user/1请求链路是网关收到请求匹配 user-route通过 LoadBalancer 从 Nacos 拉取 user-service 的实例列表选择一个实例发起转发最终调用 UserController 的查询接口。服务直接互通时也可以在业务代码中用 OpenFeign 调用而网关负责的是外部请求的统一入口和鉴权过滤。6. 装完怎么验证跑通一条链路把注册、路由、调用全串起来环境全部搭好之后用一条请求把整条链路串起来做验证。验证之前确保 Nacos 先启动然后依次启动 user-service 和 gateway-server用jps命令能看到两个 Java 进程在运行。第一步验证注册中心。打开 Nacos 控制台在服务管理页面看到user-service和gateway-server都在线实例数为 1健康状态为绿色。这一步能确认服务注册和心跳正常。第二步验证配置中心。启动 user-service 时观察日志看到类似Loading nacos data, dataId: user-service-dev.yaml的输出说明 Nacos 配置已经被拉取。如果日志里出现dataId is empty或config not found优先检查spring.application.name和profiles.active是否拼接成了正确的 dataId。第三步验证网关路由转发执行一次真实请求curl http://localhost:8080/api/user/1如果一切正常返回 JSON 结构的数据说明网关路由匹配成功StripPrefix 过滤器生效请求被转发到了 user-service。如果返回 404查看网关日志确认是路由没匹配上还是目标服务根本没注册。第四步验证数据库链路。在 user-service 日志中观察 MyBatis 是否输出了 SQL 日志确认查询真正执行到了 MySQL。如果接口返回异常检查数据库连接配置和 t_user 表是否存在。最后用 Nacos 控制台的服务详情页做一次体检点击 user-service 的实例详情确认 IP 是否正确、端口是否对应、元数据信息是否完整。这套链路验证完成后整套环境的健康状态就已经被充分确认了。从那以后我每次新起微服务项目都强制先把 Nacos 注册、网关转发、数据库查询这条链路跑一遍不跑通不写业务代码——因为环境的问题越早暴露排查成本越低定位越精准后续写业务才不会把环境问题和代码问题混在一起。这套方案对你正在搭的骨架应该能直接用上希望帮到你。本文还有配套的精品资源点击获取