SpringCloud微服务项目实战流程
一、项目概述
1.1 项目背景
本项目是一个基于SpringCloud生态的微服务架构示例项目,旨在展示企业级微服务架构的完整开发流程。项目模拟了一个简历管理与自动投递系统,包含服务注册与发现、配置中心、API网关、服务熔断、链路追踪、消息队列等核心微服务组件。
1.2 技术栈
| 分类 | 技术 | 版本 |
|---|---|---|
| 语言 | Java | 17 |
| 框架 | Spring Boot | 2.7.6 |
| 微服务 | Spring Cloud | 2021.0.9 |
| 注册中心 | Eureka | 2021.0.9 |
| 配置中心 | Spring Cloud Config | 2021.0.9 |
| 网关 | Spring Cloud Gateway | 2021.0.9 |
| 熔断 | Hystrix | 1.5.18 |
| 链路追踪 | Zipkin | 3.6.1 |
| 消息队列 | Spring Cloud Stream | 2021.0.9 |
| 认证 | OAuth2 | 2.3.5.RELEASE |
| 数据库 | MySQL | 8.0+ |
| ORM | Spring Data JPA | 2.7.6 |
1.3 模块架构
weh-resume-parent (父工程)
├── weh-service-common # 公共模块(实体类、工具类)
├── weh-cloud-eureka-server-8761 # Eureka注册中心节点1
├── weh-cloud-eureka-server-8762 # Eureka注册中心节点2
├── weh-cloud-config-9901 # Config配置中心
├── weh-cloud-gateway-9801 # API网关
├── weh-cloud-oauth2-9701 # OAuth2认证服务
├── weh-cloud-zipkin-server-9411 # Zipkin链路追踪
├── weh-cloud-hystrix-dashboard # Hystrix监控仪表盘
├── weh-cloud-hystrix-trubine # Hystrix聚合监控
├── weh-cloud-stream-producer-9090 # 消息生产者
├── weh-cloud-stream-consumer-9096 # 消息消费者1
├── weh-cloud-stream-consumer-9097 # 消息消费者2
├── weh-service-resume-8080 # 简历服务实例1
├── weh-service-resume-8081 # 简历服务实例2
├── weh-service-autodeliver-8090 # 自动投递服务实例1
└── weh-service-autodeliver-8091 # 自动投递服务实例2
架构图
层级结构
| 层级 | 组件 | 说明 |
|---|---|---|
| 客户端层 | 前端应用/移动端 | 面向用户的入口 |
| API网关层 | Spring Cloud Gateway + 过滤器 | 统一入口、请求路由、安全过滤 |
| 安全鉴权层 | OAuth2 + JWT | 统一认证授权、Token验证 |
| 服务注册发现 | Eureka双节点 | 服务注册、健康检查、负载均衡 |
| 配置中心 | Spring Cloud Config | 集中配置管理 |
| 业务服务层 | 简历服务、自动投递服务集群 | 核心业务逻辑处理 |
| 消息队列层 | Stream Producer/Consumer + RabbitMQ | 异步消息处理 |
| 监控追踪层 | Zipkin + Hystrix Dashboard + Turbine | 链路追踪、熔断监控 |
| 数据层 | MySQL + Redis | 持久化存储与缓存 |
| 公共模块 | weh-service-common | 共享实体类、工具类 |
二、环境准备
2.1 依赖环境
| 依赖 | 要求 |
|---|---|
| JDK | 17+ |
| Maven | 3.8+ |
| MySQL | 8.0+ |
| Redis | 6.0+(可选,用于OAuth2 token存储) |
2.2 Maven配置
父工程pom.xml关键配置说明:
<!-- Spring Boot依赖管理 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.7.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Spring Cloud依赖管理 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
版本兼容性说明:Spring Cloud 2021.0.9 与 Spring Boot 2.7.x 配套使用,这是经过验证的稳定组合。
三、核心模块开发流程
3.1 Eureka注册中心开发
3.1.1 创建步骤
第一步:创建Module
- 命名:
weh-cloud-eureka-server-8761 - 打包方式:
jar
第二步:添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
第三步:启动类开发
@SpringBootApplication
@EnableEurekaServer // 启用Eureka服务端
public class EurekaServer8761 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer8761.class, args);
}
}
第四步:配置文件
server:
port: 8761
spring:
application:
name: weh-cloud-eureka-server
eureka:
instance:
hostname: WehCloudEurekaServerA
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}
client:
service-url:
defaultZone: http://WehCloudEurekaServerB:8762/eureka/
register-with-eureka: true # 双节点互注册
fetch-registry: true
3.1.2 双节点高可用配置
配置hosts文件(Windows: C:\Windows\System32\drivers\etc\hosts):
127.0.0.1 WehCloudEurekaServerA
127.0.0.1 WehCloudEurekaServerB
节点2配置(端口8762):
server:
port: 8762
eureka:
instance:
hostname: WehCloudEurekaServerB
client:
service-url:
defaultZone: http://WehCloudEurekaServerA:8761/eureka/
3.1.3 启动验证
访问地址:http://localhost:8761 和 http://localhost:8762
3.2 公共模块开发
3.2.1 创建步骤
第一步:创建Module
- 命名:
weh-service-common - 打包方式:
jar
第二步:添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
3.2.2 实体类设计
Resume实体:
@Data
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "r_resume")
public class Resume {
@Id
private Long id;
private String sex;
private String birthday;
private String workYear;
private String phone;
private String email;
private String status;
private String resumeName;
private String name;
private String createTime;
private String headPic;
private Integer isDel;
private String updateTime;
private Long userId;
private Integer isDefault;
private String highestEducation;
private Integer deliverNearByConfirm;
private Integer refuseCount;
private Integer markCanInterviewCount;
private Integer haveNoticeInterCount;
private String oneWord;
private String liveCity;
private Integer resumeScore;
private Integer userIdentity;
private Integer isOpenResume; // 人才搜索-开放简历状态
}
Result响应封装:
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
private Integer code;
private String message;
private T data;
public static <T> Result<T> success(T data) {
return Result.<T>builder()
.code(200)
.message("success")
.data(data)
.build();
}
public static <T> Result<T> error(String message) {
return Result.<T>builder()
.code(500)
.message(message)
.build();
}
}
3.3 业务服务开发(简历服务)
3.3.1 创建步骤
第一步:创建Module
- 命名:
weh-service-resume-8080
第二步:添加依赖
<dependencies>
<!-- 公共模块 -->
<dependency>
<groupId>com.weh.resume</groupId>
<artifactId>weh-service-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
3.3.2 DAO层开发
public interface ResumeDao extends JpaRepository<Resume, Long> {
/**
* 根据用户ID查询默认简历
*/
Resume findByUserIdAndIsDefault(Long userId, Integer isDefault);
}
3.3.3 Service层开发
// 接口
public interface ResumeService {
Resume findDefaultResumeByUserId(Long userId);
}
// 实现类
@Service
public class ResumeServiceImpl implements ResumeService {
@Autowired
private ResumeDao resumeDao;
@Override
public Resume findDefaultResumeByUserId(Long userId) {
return resumeDao.findByUserIdAndIsDefault(userId, 0);
}
}
3.3.4 Controller层开发
@RestController
@RequestMapping("/resume")
public class ResumeController {
@Autowired
private ResumeService resumeService;
@Value("${server.port}")
private Integer port;
@RequestMapping("/openstate/{userId}")
public Integer findDefaultResumeState(@PathVariable Long userId) {
// 模拟超时场景
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return port; // 返回端口号便于观察负载均衡
}
}
3.3.5 配置文件
server:
port: 8080
spring:
application:
name: weh-service-resume
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/resume_db?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
jpa:
database: MySQL
show-sql: true
hibernate:
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
eureka:
client:
serviceUrl:
# WehCloudEurekaServerA需要在本地系统中host 【WehCloudEurekaServerA对应---> 127.0.0.1】
defaultZone: http://WehCloudEurekaServerA:8761/eureka/,http://WehCloudEurekaServerB:8762/eureka
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port}:@project.version@
3.4 业务服务开发(自动投递服务)
3.4.1 创建步骤
第一步:创建Module
- 命名:
weh-service-autodeliver-8090
第二步:添加依赖
<dependencies>
<!-- 公共模块 -->
<dependency>
<groupId>com.weh.resume</groupId>
<artifactId>weh-service-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- Eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Ribbon负载均衡 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- Hystrix熔断 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
</dependencies>
3.4.2 RestTemplate配置
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced // 启用Ribbon负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
3.4.3 Controller层开发(含Hystrix熔断)
@RestController
@RequestMapping("/autodeliver")
@DefaultProperties(defaultFallback = "findResumeOpenStateTimeoutFallback", commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "2000"),
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "8000"),
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"),
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2"),
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "3000")
})
public class AutodeliverController {
@Autowired
private RestTemplate restTemplate;
// 使用Ribbon负载均衡调用简历服务
@RequestMapping("/checkState/{userId}")
public Result<?> findResumeOpenState(@PathVariable Long userId) {
String url = "http://weh-service-resume/resume/openstate/" + userId;
Integer forObject = restTemplate.getForObject(url, Integer.class);
return Result.success(forObject);
}
// 带熔断控制的方法
@RequestMapping("/findResumeTimeout/{userId}")
@HystrixCommand(
threadPoolKey = "findResumeTimeout",
threadPoolProperties = {
@HystrixProperty(name = "coreSize", value = "1"),
@HystrixProperty(name = "maxQueueSize", value = "20")
}
)
public Result<?> findResumeTimeout(@PathVariable Long userId) {
String url = "http://weh-service-resume/resume/openstate/" + userId;
Integer forObject = restTemplate.getForObject(url, Integer.class);
return Result.success(forObject);
}
// 熔断降级方法
public Result<?> findResumeOpenStateTimeoutFallback() {
return Result.error("服务暂时不可用,请稍后重试");
}
}
3.4.4 启动类
@SpringBootApplication
@EnableDiscoveryClient // 启用服务发现
@EnableCircuitBreaker // 启用Hystrix熔断
public class ServiceAutodeliverApplication8090 {
public static void main(String[] args) {
SpringApplication.run(ServiceAutodeliverApplication8090.class, args);
}
}
3.5 API网关开发
3.5.1 创建步骤
第一步:创建Module
- 命名:
weh-cloud-gateway-9801
第二步:添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
3.5.2 配置文件
server:
port: 9801
spring:
application:
name: weh-cloud-gateway
cloud:
gateway:
routes:
# 简历服务路由
- id: resume-service-route
uri: lb://weh-service-resume
predicates:
- Path=/resume/**
# 自动投递服务路由
- id: autodeliver-service-route
uri: lb://weh-service-autodeliver
predicates:
- Path=/autodeliver/**
discovery:
locator:
enabled: true
lower-case-service-id: true
eureka:
client:
serviceUrl:
defaultZone: http://WehCloudEurekaServerA:8761/eureka/,http://WehCloudEurekaServerB:8762/eureka
3.5.3 自定义过滤器开发
@Component
public class BlackListFilter implements GlobalFilter, Ordered {
// 黑名单IP列表
private static final List<String> BLACK_LIST = Arrays.asList("127.0.0.1");
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String clientIp = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
if (BLACK_LIST.contains(clientIp)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -1; // 优先级最高
}
}
3.6 OAuth2认证服务开发
3.6.1 创建步骤
第一步:创建Module
- 命名:
weh-cloud-oauth2-9701
第二步:添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
3.6.2 用户详情服务
@Service
public class JdbcUserDetailsService implements UserDetailsService {
@Autowired
private UsersRepository usersRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Users user = usersRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("用户不存在");
}
return new User(user.getUsername(), user.getPassword(), AuthorityUtils.createAuthorityList("ROLE_USER"));
}
}
3.6.3 授权服务器配置
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
// 配置客户端信息存储
@Bean
public ClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
// 配置token存储
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService());
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService)
.tokenStore(tokenStore());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
}
3.7 链路追踪(Zipkin)
3.7.1 创建步骤
第一步:创建Module
- 命名:
weh-cloud-zipkin-server-9411
第二步:添加依赖
<dependencies>
<dependency>
<groupId>io.zipkin</groupId>
<artifactId>zipkin-server</artifactId>
<version>3.6.1</version>
</dependency>
<dependency>
<groupId>io.zipkin</groupId>
<artifactId>zipkin-autoconfigure-ui</artifactId>
<version>3.6.1</version>
</dependency>
</dependencies>
3.7.2 启动类
@SpringBootApplication
@EnableZipkinServer
public class ZipkinServerApplication9411 {
public static void main(String[] args) {
SpringApplication.run(ZipkinServerApplication9411.class, args);
}
}
3.7.3 客户端配置(业务服务)
spring:
zipkin:
base-url: http://localhost:9411
sleuth:
sampler:
probability: 1.0 # 采样率
3.8 消息队列(Spring Cloud Stream)
3.8.1 生产者开发
第一步:创建Module
- 命名:
weh-cloud-stream-producer-9090
第二步:添加依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rabbit</artifactId>
</dependency>
</dependencies>
第三步:消息发送接口
public interface MyMessageProducer {
String OUTPUT = "myOutput";
@Output(OUTPUT)
MessageChannel output();
}
第四步:消息发送实现
@Service
public class MyMessageProducerImpl {
@Autowired
private MyMessageProducer myMessageProducer;
public void sendMessage(String message) {
myMessageProducer.output().send(MessageBuilder.withPayload(message).build());
}
}
第五步:配置文件
server:
port: 9090
spring:
application:
name: weh-cloud-stream-producer
cloud:
stream:
bindings:
myOutput:
destination: myExchange
content-type: application/json
3.8.2 消费者开发
第一步:创建Module
- 命名:
weh-cloud-stream-consumer-9096
第二步:消息接收服务
@Service
public class MessageConsumerService {
@StreamListener("myInput")
public void receive(String message) {
System.out.println("消费者接收到消息: " + message);
}
}
第三步:配置文件
server:
port: 9096
spring:
application:
name: weh-cloud-stream-consumer
cloud:
stream:
bindings:
myInput:
destination: myExchange
content-type: application/json
四、服务启动顺序
1. Eureka Server 8761 (必须最先启动)
2. Eureka Server 8762 (双节点互注册)
3. Config Server 9901 (配置中心)
4. Zipkin Server 9411 (链路追踪)
5. OAuth2 Server 9701 (认证服务)
6. Gateway 9801 (API网关)
7. Hystrix Dashboard (熔断监控)
8. 业务服务 (resume、autodeliver)
9. Stream Producer/Consumer (消息队列)
五、服务访问测试
5.1 Eureka控制台
- http://localhost:8761
- http://localhost:8762
5.2 简历服务
- 直接访问: http://localhost:8080/resume/openstate/1
- 网关访问: http://localhost:9801/resume/openstate/1
5.3 自动投递服务
- 直接访问: http://localhost:8090/autodeliver/checkState/1
- 网关访问: http://localhost:9801/autodeliver/checkState/1
5.4 Zipkin控制台
- http://localhost:9411/zipkin/
5.5 Hystrix Dashboard
- http://localhost:9000/hystrix
5.6 OAuth2获取Token
POST http://localhost:9701/oauth/token
Content-Type: application/x-www-form-urlencoded
client_id=client
client_secret=secret
grant_type=password
username=admin
password=123456
六、关键技术点总结
| 技术组件 | 核心作用 | 关键配置 |
|---|---|---|
| Eureka | 服务注册与发现 | @EnableEurekaServer / @EnableDiscoveryClient |
| Ribbon | 客户端负载均衡 | @LoadBalanced + RestTemplate |
| Hystrix | 服务熔断降级 | @HystrixCommand + 线程池配置 |
| Gateway | API网关路由 | spring.cloud.gateway.routes |
| Config | 分布式配置中心 | bootstrap.yml + Git仓库 |
| Zipkin | 分布式链路追踪 | spring.zipkin.base-url |
| OAuth2 | 统一认证授权 | @EnableAuthorizationServer |
| Stream | 消息驱动 | @Output / @Input / @StreamListener |
七、注意事项
- 端口冲突:确保各服务使用不同端口,建议按规划端口启动
- MySQL连接:确保MySQL服务正常运行,数据库配置正确
- Hosts配置:双节点Eureka需要配置hosts文件
- 依赖版本:Spring Cloud与Spring Boot版本必须匹配
- 网络环境:确保各服务间网络畅通
- 启动顺序:严格按照启动顺序启动服务,避免依赖问题
八、扩展建议
- 服务监控:集成Prometheus + Grafana进行指标监控
- 日志聚合:引入ELK栈进行日志收集与分析
- 服务网格:考虑引入Istio进行更精细的流量管理
- 容器化:使用Docker + Kubernetes进行服务编排
- 持续集成:配置Jenkins/GitLab CI进行自动化构建部署
- 分布式事务:引入Seata解决跨服务事务问题
675



被折叠的 条评论
为什么被折叠?



