ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

JDK17+Spring Boot 3+Nacos搭建微服务开发环境实战指南

JDK17+Spring Boot 3+Nacos搭建微服务开发环境实战指南 最近帮同事搭一套新的微服务开发环境顺手把整个流程记录了下来在 IntelliJ IDEA 里面用 JDK17 跑 Spring Boot 3再配合 Nacos 做服务注册和配置中心。整套环境从零到两个服务互相调用、配置动态刷新全部跑通花了一天时间。中间踩了不少坑有些问题百度上搜出来的答案已经过时了专门整理成这篇图文教程给准备从 Spring Boot 2.x 升级到 3.x、或者第一次接触 Nacos 的朋友做个参考。下面的内容会覆盖环境准备、Nacos 安装与安全配置、Spring Boot 工程创建、注册中心接入、配置中心动态刷新最后是一份宝贵的问题排查记录。跟着做不仅能跑通还能理解每一步为什么要这么配以后换个版本组合也知道怎么查问题。1. 搭建前的环境准备与版本选型1.1 JDK17 与 Spring Boot 版本怎么搭配先说版本选型这是很多人第一步就栽跟头的地方。JDK17 是 Java 17 LTS 版本2021 年 9 月发布现在很多公司的生产环境已经从 JDK8 切到 JDK17 了。Spring Boot 这边如果你打算用 JDK17最推荐的是Spring Boot 3.x因为 Spring Boot 3.0 开始官方就把 JDK17 作为基础版本整个框架是在 Jakarta EE 9 之上重构的注意javax.*变成了jakarta.*。有人会问Spring Boot 2.7 也支持 JDK17能不能用能用但我不建议新项目这么干。Spring Boot 2.7 虽然能跑在 JDK17 上但它骨子里还是为 JDK8 设计的很多第三方库的兼容性问题会在后面的开发中慢慢冒出来。既然是新环境直接上 Spring Boot 3 JDK17 是最省心的。Spring Cloud 和 Spring Cloud Alibaba 的版本也要对应好。我这次实测下来的稳定组合是组件版本JDK17Oracle JDK 或 Adoptium/Temurin 均可Spring Boot3.2.xSpring Cloud2023.0.xSpring Cloud Alibaba2023.0.1.xNacos Server2.3.x 稳定版IDEA2023.2 及以上社区版也可以Maven3.8.x 或 3.9.x这个组合是经过实际验证的Spring Cloud Alibaba 2023.0.1.x 对应 Spring Cloud 2023.0.x底层内置的 nacos-client 版本是 2.3.x跟 Nacos Server 2.3.x 配合最默契。如果你用了 Nacos Server 2.2.x 或者更老的 1.x客户端接口会有差异后面服务注册可能会报各种奇怪的错。JDK17 下载安装本身不难Windows 用户直接去 Adoptium 官网或者 Oracle 官网下载安装包安装完成后设置JAVA_HOME环境变量为安装路径比如C:\Program Files\Microsoft\jdk-17.x.x然后把%JAVA_HOME%\bin加到Path里。这里有个小细节Windows 上安装 Oracle JDK 有时候会自动把C:\Program Files\Common Files\Oracle\Java\javapath排在环境变量前面导致终端里java -version显示的版本跟你装的 JDK17 不一样。出现这种情况把 Path 里的javapath删掉或者把你的%JAVA_HOME%\bin调整到最前面即可。1.2 IDEA 与 Maven 的基础配置IDEA 版本方面社区版Community Edition完全够用。之前有些教程说社区版不能创建 Spring Boot 项目那是老黄历了。IDEA 2023.1 之后的社区版已经内置了 Spring Initializr 支持新建项目可以直接选 Spring Boot 版本生成工程。如果你用的版本比较旧也可以到 start.spring.io 网站上生成项目压缩包再导入 IDEA效果一样。IDEA 里用 JDK17 有三个地方要检查漏一个都会出问题Project Structure 里的 Project SDKFile - Project Structure - Project - SDK选择 17。Project Structure 里的 Language Level同样在 Project 菜单里Language Level 选择 17。如果选低了代码里用不了 JDK17 新语法。Settings 里的 Maven 配置File - Settings - Build, Execution, Deployment - Build Tools - Maven这里有个Runner - JRE选项也要选 17。Maven 这边建议先配置好阿里云镜像不然 Spring Boot 3 的依赖下载会让你怀疑人生。在 Maven 安装目录conf/settings.xml里添加以下 mirrormirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror配置完镜像后IDEA 的 Maven 设置里要把User settings file指向这个settings.xml然后点Reload All Maven Projects让设置生效。这里容易踩的坑是IDEA 默认会用内置的 Maven而不是你下载的 Maven所以你在命令里用的 Maven 和 IDE 里用的一致不一致要看清楚建议用 IDEA 内置的 Maven 就行只需要把settings.xml指对。2. Nacos 安装、启动与安全配置2.1 下载与单机启动NacosDynamic Naming and Configuration Service是阿里巴巴开源的服务发现和配置管理平台在 Java 微服务生态里用得很多。它的作用可以用一句话概括让服务互相能找到对方并且能让配置在不重启服务的情况下动态更新。去 Nacos 官网 GitHub Releases 页面下载最新稳定版我用的是 2.3.2。下载nacos-server-2.3.2.zip或者.tar.gz即可。Windows 用户解压后进入bin目录注意 Nacos 默认是集群模式启动单机开发必须加-m standalone参数startup.cmd -m standaloneMac / Linux 用户用sh startup.sh -m standalone启动成功后浏览器访问http://localhost:8848/nacos默认用户名和密码都是nacos/nacos。注意路径里的/nacos前缀很多新手直接访问 8848 端口发现是白屏就是因为少了这个上下文路径。Nacos 默认会使用内嵌的 Derby 数据库存储配置信息这个对开发来说够用重启数据也不会丢太多。但如果你打算一直用下去建议提前切换到 MySQL。在conf/application.properties里把数据源改成 MySQL再执行conf/mysql-schema.sql初始化数据库表。我这次在开发环境就是用的 Derby就不展开 MySQL 切换了不过建议正式环境务必切 MySQL不然后面配置多了、集群节点一多Derby 的并发和一致性都会成问题。2.2 开启鉴权并修改默认密码Nacos 默认没有开启鉴权这意味着任何能访问你 8848 端口的人都能看到你所有服务的注册信息、改你的配置这是很大的安全隐患。社区里常说的“Nacos namespaces 未授权访问漏洞”“Nacos 配置泄露”绝大多数就是因为默认没开鉴权。开启鉴权的方法在conf/application.properties里添加以下配置nacos.core.auth.enabledtrue nacos.core.auth.plugin.nacos.token.secret.keyVGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMDEyMzQ1Njc4OQ nacos.core.auth.server.identity.keyserverIdentity nacos.core.auth.server.identity.valueexampleServerIdentitytoken.secret.key这个配置容易踩坑Nacos 2.x 要求这个值必须是 Base64 编码的字符串且原文长度不低于 32 字节否则启动时会报错或者鉴权不生效。上面的示例值是可以用生产环境建议自己生成一个随机值随便找个在线工具把一段 32 字符以上的随机字符串做 Base64 编码即可。配置完成后重启 Nacos再用浏览器登录会发现登录接口多了鉴权检查。启用鉴权后你的 Spring Boot 服务在连接 Nacos 时也需要带上用户名密码这个在后面的客户端配置里会讲到。另外登录后第一件事就是把默认密码改掉。在 Nacos 控制台右上角“修改密码”里操作即可。社区里有个高频报错“nacos 页面修改密码报错 request error, please try again later!”这个我遇到过大多是 Nacos 客户端版本和 Server 版本不一致导致的或者是在鉴权开启之前就登录了老会话。遇到这个报错先确认 Server 和 nacos-client 版本一致再试试清除浏览器缓存、重新登录。2.3 Docker Compose 方式部署 Nacos可选如果你用的是 Mac 或者 Linux本地装了 Docker也可以直接用 Docker Compose 起一个 Nacos干净又方便。这次我在一台 Ubuntu 环境测试时用的就是 Docker 方式写个docker-compose.ymlservices: nacos: image: nacos/nacos-server:v2.3.2 container_name: nacos environment: - MODEstandalone - NACOS_AUTH_ENABLEtrue - NACOS_AUTH_TOKENVGhpc0lzTXlDdXN0b21TZWNyZXRLZXkwMDEyMzQ1Njc4OQ - NACOS_AUTH_IDENTITY_KEYserverIdentity - NACOS_AUTH_IDENTITY_VALUEexampleServerIdentity ports: - 8848:8848 - 9848:9848然后执行docker compose up -d这里有个 Nacos 2.x 的端口说明Nacos 2.x 客户端默认会使用9848端口做 gRPC 通信如果只映射了 8848 没映射 9848服务注册和发现都会失败。这个报错在日志里往往很模糊比如 timeout 或者 connection reset非常容易被忽略。建议在搭建环境前就把这个端口映射加上。启动完成后一样的地址登录控制台。Docker 方式的好处是以后不想用了docker compose down就清理干净了不会像本机解压部署那样留一堆残留进程。3. 创建 Spring Boot 工程并接入 Nacos3.1 Spring Boot 工程的创建打开 IDEAFile - New - Project选择Spring Initializr。这里注意Name 填user-service后面做服务提供方。Type 选 Maven。Language 选 Java。Java 版本选 17。依赖这里只需要加一个Spring Web剩下的 Nacos 相关依赖我们后面手动加因为 Spring Initializr 里的 Alibaba 依赖列表不一定跟你的 Spring Boot 版本匹配手动加更可控。创建完工程后确认pom.xml里 Spring Boot 版本是不是 3.2.x。然后手动添加以下依赖parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.2.5/version /parent dependencies dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId version2023.0.1.0/version /dependency /dependencies注意Spring Boot 3 和 Spring Cloud 的依赖管理不用再像 Spring Boot 2 那样引入spring-cloud-dependencies的import类型依赖了不对其实还是需要的。Spring Boot 3 的 parent 里并不会帮你管理 Spring Cloud 的版本所以要再加两个 dependencyManagementdependencyManagement dependencies dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version2023.0.1/version typepom/type scopeimport/scope /dependency dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-dependencies/artifactId version2023.0.1.0/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement这样依赖版本就由 BOM 统一管住了你的业务依赖里不用写版本号。如果你不想手动管理版本直接复制这段就行。3.2 引入 Nacos 注册中心配置创建一个 Spring Boot 服务接入 Nacos核心配置在application.yml里。我这次用的配置如下server: port: 8080 spring: application: name: user-service cloud: nacos: discovery: server-addr: 127.0.0.1:8848 username: nacos password: nacos namespace: public config: server-addr: 127.0.0.1:8848 username: nacos password: nacos file-extension: yml关键点展开讲spring.application.name必须设置。Nacos 控制台里显示的服务名就是从这里取的。如果没有这个配置注册到 Nacos 的服务会显示为unknown。username和password如果你按前面教程开启了鉴权这里必须带上账号密码否则服务启动时会报 403 或者无法注册。namespace有两个选择public默认命名空间或者具体命名空间 ID。如果你没特意创建命名空间用public就行。如果填了不存在的命名空间 ID服务注册界面可能什么都看不到。Nacos 地址的配置有两个位置一个是discovery注册中心一个是config配置中心两者可以指向同一个 Nacos Server也可以分开。这里提醒一个容易踩的坑Spring Boot 3 里Nacos config 相关功能只依赖spring-cloud-starter-alibaba-nacos-config而注册中心依赖是spring-cloud-starter-alibaba-nacos-discovery。如果你没有引入 config 依赖spring.cloud.nacos.config配置会被忽略不会报错但不会生效。我在第一次测试的时候只引入了 discovery结果动态刷新一直不生效排查了半天。3.3 注册中心接入验证加入依赖和配置后启动user-service。启动成功后再写一个最简单的接口用于验证RestController public class UserController { GetMapping(/user/hello) public String hello() { return Hello from user-service; } }启动完成后打开 Nacos 控制台http://localhost:8848/nacos进入“服务管理 - 服务列表”如果能看到user-service的实例并且状态为“健康”说明注册中心已经打通了。如果服务列表里没有东西优先看日志。Nacos 客户端启动时会输出类似这样一行日志Nacos registry, DEFAULT_GROUP user-service 127.0.0.1:8080 register finished如果看到这一行说明客户端已经注册成功了控制台没显示通常是命名空间选错了检查一下控制台左上角选的是不是public。如果没有这行日志就要看前面有没有异常常见的是 9848 端口不通、鉴权失败403、或者 Nacos 版本不兼容。4. 配置中心接入与动态刷新4.1 Nacos 配置中心的数据组织方式Nacos 作为配置中心数据是分层的命名空间Namespace - 分组Group - 配置Data ID。这个概念理解了后面配置管理就顺了。Namespace用来做环境隔离比如开发、测试、生产各一个命名空间相互之间配置不干扰。默认是public。Group默认是DEFAULT_GROUP。可以在同一个命名空间下按业务域拆分组。Data ID具体某份配置。默认的格式是${spring.application.name}.${file-extension}。比如user-service.yml。对于单个服务最常用的是直接在 Nacos 里创建一条 Data ID 为user-service.yml的配置这个 Data ID 会被 Spring Boot 服务自动加载。这是 Nacos 约定优于配置的体现因为spring.application.name加上文件后缀正好组成默认的 Data ID不需要额外指定。4.2 动态刷新配置实战在user-service的pom.xml里加配置中心依赖dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-config/artifactId version2023.0.1.0/version /dependency注意Spring Boot 3 默认不会主动加载bootstrap.yml文件需要额外的 bootstrap 依赖。简单点说我们在配置中心加载配置用得最多的方式是spring.config.import即在application.yml里加一行spring: config: import: optional:nacos:user-service.yml它的意思是应用启动时把 Nacos 里 Data ID 为user-service.yml的配置导入进来。optional:前缀表示哪怕 Nacos 连不上应用也能启动不会因为配置中心暂时不可用就直接挂掉。然后咱们在 Nacos 控制台新增一条配置Data IDuser-service.ymlGroupDEFAULT_GROUP配置格式YAML配置内容加一条测试配置user: nickname: zhangsan age: 25在代码里写一个验证用的 ControllerRestController RefreshScope public class ConfigController { Value(${user.nickname:default}) private String nickname; Value(${user.age:0}) private int age; GetMapping(/config) public String config() { return nickname nickname , age age; } }关键点是RefreshScope不加这个注解的话配置虽然能从 Nacos 拉下来但修改后不会自动刷新到 Bean 里。加上之后当你修改 Nacos 里的配置并发布Spring Cloud 会通过事件机制刷新这个 Bean再次请求/config接口就能拿到新值了。这里有个容易犯的错ConfigurationProperties和Value的刷新机制不一样。Value配合RefreshScope可以刷新ConfigurationProperties如果类本身没有被RefreshScope标注即使被注入到其他 Bean 里刷新也不会生效。建议在项目里优先用ConfigurationProperties把一组配置封装成类然后在类上加上RefreshScope代码更整洁Component ConfigurationProperties(prefix user) RefreshScope public class UserProperties { private String nickname; private int age; // getter and setter 省略 }启动user-service访问/config如果返回nicknamezhangsan, age25说明配置中心加载成功。然后回 Nacos 控制台把nickname改成lisi点发布再刷新请求几秒内就能看到新值。我实测时大概有 3-5 秒的延迟因为客户端默认配置了长轮询如果你的要求是秒级甚至毫秒级可以调小spring.cloud.nacos.config.timeout之类参数但是没必要开发环境默认就很好用。5. 服务发现与调用实战5.1 再创建一个消费者服务光有服务注册、没有服务调用等于只搭了一半。咱们再来一个order-service让它通过 Nacos 发现user-service并调用接口。创建方式和前面一样Spring Initializr 新建项目order-service端口设成 8081。pom.xml里引入跟前面一样的 discovery 依赖。代码里关键的配置是消费端的服务发现和负载均衡。Spring Cloud 2023.0.x 默认使用的是 LoadBalancer 组件不用再单独引入 RibbonRibbon 已经进入维护状态了。咱们在启动类里声明一个带负载均衡的RestTemplateSpringBootApplication public class OrderServiceApplication { public static void main(String[] args) { SpringApplication.run(OrderServiceApplication.class, args); } Bean LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }LoadBalanced是点睛之笔。它会让 RestTemplate 发请求时自动把“服务名”解析成真实的 IP:Port然后从 Nacos 拿到user-service的实例列表做负载均衡。如果忘了加这个注解直接写http://user-service/user/hello运行时会报“UnknownHostException”。写一个测试接口RestController public class OrderController { Resource private RestTemplate restTemplate; GetMapping(/order/call) public String call() { String url http://user-service/user/hello; return restTemplate.getForObject(url, String.class); } }启动order-service访问http://localhost:8081/order/call返回Hello from user-service就说明服务发现和调用全部打通了。5.2 验证负载均衡与自我保护为了直观看到负载均衡可以同时启动两个user-service实例一个 8080 端口一个 8082 端口启动时用--server.port8082参数覆盖。两个实例都注册到 Nacos 后控制台的服务列表里user-service会显示两个实例。连续访问/order/call多次你会看到请求在两个实例之间轮询分发日志里两个服务各自收到部分请求。这个负载均衡能力是客户端侧做的不需要额外的网关或者代理生产环境做多实例部署时这一点很关键。再提一个 Nacos 的自我保护机制当某个服务实例心跳消失比如被强杀默认会保留 15 秒左右才把它从健康实例列表移除。所以如果你测出“服务明明停了但接口还能调通”的现象别慌等十几秒再试。这个时间可以在服务端的配置里调整但开发环境用默认值就够了。6. 常见问题与排查技巧实录6.1 版本不匹配类问题这一部分是全流程里踩坑最多的地方也是社区里问得最多的。我做了一个速查表基本覆盖了常见报错报错现象原因解决办法启动报NoSuchMethodError或者ClassNotFoundException一般是 nacos-client 版本和 Spring Cloud Alibaba 版本不匹配用 BOM 统一管理版本别手动指定不兼容的 nacos-client服务注册到 Nacos 控制台看不到命名空间不对 / 8848 与 9848 端口未都通检查控制台命名空间、确认 9848 端口已映射连接 Nacos 报 403 / Access denied服务端开了鉴权客户端没配账号密码在application.yml的 discovery/config 里配置username和passwordRefreshScope注解加了还是不刷新配置中心依赖没引入 / Data ID 不对 / 没走 spring.config.import检查spring-cloud-starter-alibaba-nacos-config依赖确认import的 Data ID启动时说找不到nacos config配置Spring Boot 3 没识别 bootstrap.yml用spring.config.import或者在打包时引入 bootstrap 相关依赖这里特别强调一个容易混淆的地方Nacos 服务端版本、nacos-client 客户端版本、Spring Cloud Alibaba 版本这三者是三个独立的东西。网上很多教程直接给一个 nacos-client 的坐标让你引入但 Spring Cloud Alibaba 自己内置了客户端版本你手动覆盖它极容易引发接口不兼容。尽量别手动引入 nacos-client让 Spring Cloud Alibaba BOM 来管理。6.2 连接与启动类问题9848 端口不通是最隐蔽的问题。Nacos 2.x 从客户端到服务端有一半通信走 gRPC端口是 884810009848。本机测试通常没问题但如果你以后把服务部署到远程服务器防火墙只开了 8848服务注册就会时好时坏日志里出现Failed to request to server: /127.0.0.1:8848, code: 501, message: Not Implemented看到501 Not Implemented大概率就是这个原因。解决办法就是安全组或者防火墙同时放行 8848 和 9848。启动顺序问题Nacos Server 最好先启动再启动 Spring Boot 服务。虽然客户端配置了optional:后连不上 Nacos 也能启动但服务注册时机错过之后要等心跳重连往往过了 30 秒到 1 分钟才在控制台出现容易让人误以为配置有问题。IDEA 社区版创建 Spring Boot 工程的问题社区版确实能用但如果你用的版本较早2022.x 之前创建项目时没有 Spring Initializr 选项可以去 start.spring.io 生成项目然后 File - Open 导入即可。公司如果有安全要求不能访问外网也可以用镜像站点比如阿里云的https://start.aliyun.com生成的工程结构和官方的一致但注意这个站点的 Spring Boot 版本列表偏老可能没有 3.2.x生成后手动改 parent 版本即可。6.3 配置与安全类问题关于 Nacos 页面那个“修改密码报错 request error, please try again later!”我这次也碰到一次。原因是 Nacos Server 是 2.2.0而浏览器缓存的登录 Token 是开启鉴权之前的旧 Token导致请求鉴权不过。解决办法很简单清掉浏览器缓存重新登录再修改密码。如果你在生产环境用 Nacos强烈建议把以下几件事做了开启鉴权修改默认密码。配置访问白名单限制 8848 端口的来源 IP。定期备份 Nacos 的数据库如果用 MySQL 的话。重要配置拆成多个 Data ID避免超大配置块。另外很多人问 Nacos 的替代方案。如果是中小项目不想引入额外组件直接用 Spring Cloud Config Git 也可以但 Nacos 胜在“注册中心 配置中心”二合一控制台界面也直观运维成本低。如果是 K8s 环境还可以考虑使用 K8s 原生的 ConfigMap 服务发现不过那套体系跟 Spring Cloud 生态融合程度不如 Nacos。最后再分享一个小技巧Nacos 控制台左侧菜单里有一个“监听查询”可以看当前配置被哪些服务订阅了。当你在纠结“配置到底有没有被加载”的时候去监听查询里搜 Data ID如果能看到对应的客户端 IP说明配置已经分发下去了问题一定出在应用侧的刷新逻辑上而不是配置通道。这个功能知道的人不多排查问题却非常实用建议先记下来。这套环境搭完之后后面还可以继续扩展加一个 Spring Cloud Gateway 做统一入口或者把配置中心的配置按环境拆分到不同命名空间再或者接一套 Nacos 集群保证高可用。不过对于刚上手的人来说先把注册中心和配置中心这两个核心能力玩熟比什么都重要。
返回列表