搭建Spring Cloud环境时,最先要处理的是版本规划。如果Spring Boot与Spring Cloud版本不对应,项目可能在启动阶段就报类找不到或依赖冲突。本文使用Spring Boot 2.7.12与Spring Cloud 2021.0.5这个组合,基于JDK 11和Maven 3.8来演示从零开始的环境搭建流程。整套流程会覆盖父工程、Eureka注册中心、服务提供者与服务消费者四个模块,并给出常见问题的定位方式。

一、环境准备与版本选型为什么重要
Spring Cloud不是一个单独运行的框架,它建立在Spring Boot之上,因此两者的版本必须严格匹配。举例来说,Spring Cloud 2021.0.x系列对应Spring Boot 2.6.x到2.7.x,Spring Cloud 2022.0.x则只支持Spring Boot 3.0.x。如果只升级Spring Boot而不调整Spring Cloud版本,很可能出现依赖下载失败或启动时类找不到的问题。JDK方面,Spring Boot 2.x通常使用JDK 8或11,Spring Boot 3.x要求JDK 17及以上,所以第一步就要把JDK、Maven和IDEA的编译环境统一起来。
在IDEA中建议先检查Project Structure里的SDK版本、Maven的settings.xml本地仓库路径以及Java Compiler版本。Maven可以单独安装,也可以用IDEA自带的版本,但需要保证命令行和IDEA内部使用同一个settings.xml,否则很容易出现依赖下载路径不一致。创建项目前先在终端执行mvn -version确认Maven能够正常读取JDK,避免后续构建时因为环境变量缺失而失败。
二、创建Maven父工程并统一依赖管理
实际开发中通常不会只创建一个服务就结束,后续还会加入配置中心、网关、链路追踪等模块。如果每个模块都单独维护Spring Boot和Spring Cloud版本,升级时会非常痛苦。因此第一步先创建一个打包方式为pom的父工程,把所有公共依赖版本集中管理。父工程本身不写业务代码,只负责声明版本和模块结构。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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>com.example</groupId>
<artifactId>springcloud-demo</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<spring-boot.version>2.7.12</spring-boot.version>
<spring-cloud.version>2021.0.5</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
这里用dependencyManagement统一管理版本,子模块再声明依赖时不需要重复写version。比如后续创建Eureka服务端模块时,只需要写spring-cloud-starter-netflix-eureka-server的groupId和artifactId,版本会自动从父工程继承。这样做的好处是将来升级Spring Cloud版本时,只修改父工程中的一处配置即可。
父工程创建完成后,在结构上规划三个子模块:eureka-server负责服务注册与发现,provider-service对外提供REST接口,consumer-service通过注册中心找到提供者并完成调用。三个模块都作为父工程的子模块存在,每个模块仍然独立打包、独立启动。
三、搭建Eureka注册中心模块
Eureka注册中心是Spring Cloud体系中比较传统的服务治理组件,虽然目前也出现了Nacos、Consul等替代方案,但对于入门来说Eureka的配置最简单,便于观察服务注册状态。首先创建eureka-server模块,在pom文件中引入服务端依赖。
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
然后编写启动类,使用@EnableEurekaServer开启注册中心功能。配置文件要指定服务端口为8761,同时关闭注册中心向自己注册的行为,因为当前只有一个Eureka节点,没有必要把自己也当成客户端注册进去。
package com.example.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
启动eureka-server模块后,浏览器访问http://127.0.0.1:8761/ 可以看到Eureka控制台。如果页面无法打开,优先检查端口是否被占用,以及是否因为代理设置导致127.0.0.1被绕过。首次访问页面可能空白几秒,这是正常初始化过程,稍等片刻再刷新即可。
四、编写服务提供者与消费者
服务提供者provider-service需要同时引入Web依赖和Eureka客户端依赖。Web依赖用于暴露REST接口,Eureka客户端依赖则让该服务启动后自动向注册中心登记。创建该模块后先写一个简单的Controller,返回一段固定文本即可。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
package com.example.providerservice.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello from provider";
}
}
package com.example.providerservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProviderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderServiceApplication.class, args);
}
}
server:
port: 8081
spring:
application:
name: provider-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
接着创建消费者consumer-service。消费者需要依赖Web、Eureka客户端以及Spring Cloud LoadBalancer。在Spring Cloud 2021.0.x版本中,Ribbon已经进入维护模式,默认负载均衡由Spring Cloud LoadBalancer提供。为了让RestTemplate根据服务名发起调用,需要给RestTemplate加上@LoadBalanced注解。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
package com.example.consumerservice.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
package com.example.consumerservice.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class ConsumerController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/call")
public String call() {
return restTemplate.getForObject("http://provider-service/hello", String.class);
}
}
package com.example.consumerservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConsumerServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerServiceApplication.class, args);
}
}
server:
port: 8082
spring:
application:
name: consumer-service
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:8761/eureka/
在消费者中调用地址写的是服务名provider-service,而不是IP和端口。RestTemplate在发起请求前会通过负载均衡器从Eureka中查询该服务名对应的实例列表,再选择合适的节点转发。整个过程对业务代码透明,不需要手动拼接主机地址。
五、启动顺序与常见问题排查
启动顺序应固定为:先启动eureka-server,等待控制台正常显示后,再启动provider-service,最后启动consumer-service。因为服务提供者需要在启动时向注册中心登记,如果注册中心还没有准备好,客户端会持续重试连接,日志里会出现Connection refused字样,这是正常的重试过程,但不建议长期运行在注册中心不可用的状态下。
常见问题主要集中在下面几类:
- 版本冲突:表现为编译通过但启动报NoSuchMethodError或ClassNotFoundException,排查方式是检查父工程中的Spring Boot和Spring Cloud版本是否匹配。
- 端口占用:8761、8081、8082任一端口被其他进程占用都会导致启动失败,可以在IDEA的Run面板中查看具体端口冲突信息。
- 服务注册不上:检查客户端配置文件中的defaultZone地址是否与注册中心地址一致,注意地址末尾需要带/eureka/路径。
- 服务名解析失败:调用http://provider-service/hello时如果报UnknownHostException,说明消费者没有正确读取Eureka实例列表,检查RestTemplate是否配置了@LoadBalanced。
- Eureka自我保护:当某个服务心跳丢失比例超过阈值时,Eureka会进入自我保护模式,此时页面可能显示服务名但实例状态异常。开发阶段可以适当缩短心跳周期,但不要随意在配置中关闭自我保护,避免掩盖真实故障。
最后还要注意,每次修改父工程pom后,需要让IDEA重新导入Maven依赖,否则新增的子模块或依赖可能不被识别。多个模块同时开发时,每个模块都可以独立启动,只要注册中心保持运行,服务之间的调用关系就能持续生效。完成这套流程后,你就已经搭好了一个可运行的最小Spring Cloud微服务闭环,后续再接入配置中心、网关或熔断器都会更加顺畅。
Spring Cloud环境搭建微服务修改时间:2026-09-18 05:34:41