Appearance
微服务项目
前置知识
在阅读本章前,你需要了解:Java基础语法、Spring Boot基础、RESTful API概念
为什么需要微服务架构?
想象你正在维护一个庞大的电商系统,所有功能都塞在一个庞大的“单体”应用里:商品管理、订单处理、用户服务…代码越来越复杂,一次小改动都可能引发大范围的影响,导致部署变得缓慢且风险高。更严重的是,团队协作也变得低效,每个开发组都在争抢同一个庞大的代码库。
这时,微服务架构(Microservices)派上用场了。它帮你把大系统拆分成一组小而独立的服务,每个服务负责自己的业务领域,可以独立开发、测试、部署。服务之间通过轻量级通信(通常是HTTP/REST或消息队列)协作。这样一来,开发速度提升,系统更灵活抗风险,技术栈升级也更简单。
不过,微服务带来了新的挑战:服务如何拆分?它们之间怎么通信?配置管理怎么办?服务如何被发现?这些是我们这章要解决的核心问题。
服务拆分
什么是服务拆分?
服务拆分就是把一个大应用切分成多个小服务,每个服务聚焦于单一业务能力。换句话说,我们把不同职责像“拼图”一样拆开,让它们独立运行和演进。
为什么需要拆分?
- 降低服务复杂度,更易维护
- 让团队可以并行开发
- 支持独立部署,减少影响面
- 便于灵活选型技术栈
简单示例:将用户管理拆成独立服务
假设之前的单体应用UserService和OrderService混在一起,现在把用户管理单独做成UserService。
java
package com.example.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@SpringBootApplication
@RestController
@RequestMapping("/users")
public class UserServiceApplication {
// 简单内存存储用户数据
private final Map<String, String> users = new ConcurrentHashMap<>();
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
@PostMapping("/{id}")
public String addUser(@PathVariable String id, @RequestBody String name) {
users.put(id, name);
return "User added";
}
@GetMapping("/{id}")
public String getUser(@PathVariable String id) {
return users.getOrDefault(id, "User not found");
}
}这段代码做了什么:
- 搭建了一个Spring Boot服务,监听
/users接口。 - 用内存存储模拟用户数据。
- 提供添加用户和查询用户的接口。
我们刚刚实现了把“用户管理”服务拆出来,代码清晰且职责单一。
小结
- 服务职责单一是拆分的基础
- 简单HTTP接口实现服务独立访问
服务间通信
拆完服务,关键问题来了:它们如何互相“聊”?
两种通信方式
同步通信(通常用REST API或gRPC)
- 请求方发起调用,等待响应
- 简单直观,但请求阻塞,耦合较紧
异步通信(消息队列、事件驱动)
- 使用消息中间件,解耦服务
- 扩展性好,但实现复杂度较高
先从同步通信入手,大家最熟悉,也最容易理解。
代码示例:订单服务调用用户服务获取用户名
订单服务先调用用户服务接口,获取用户名后才能处理订单。
java
package com.example.orderservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@RestController
@RequestMapping("/orders")
public class OrderServiceApplication {
private final RestTemplate restTemplate = new RestTemplate();
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
@GetMapping("/{orderId}/username/{userId}")
public String getOrderUserName(@PathVariable String orderId, @PathVariable String userId) {
// 调用用户微服务,获取用户名
String userServiceUrl = "http://localhost:8081/users/" + userId;
String userName = restTemplate.getForObject(userServiceUrl, String.class);
return "Order " + orderId + " belongs to user: " + userName;
}
}这段代码做了什么:
- 创建OrderService服务。
- 使用Spring的RestTemplate同步调用用户服务接口(假设用户服务跑在8081端口)。
- 返回订单和对应用户名。
小结:
- 微服务间通信关键在地址和接口规范
- 需要确保调用的服务可用
配置中心
你可能发现,服务间调用时,地址硬编码了(刚才写了http://localhost:8081)。在真实场景中,微服务实例多、IP动态变化,如何管理地址和配置呢?
为什么需要配置中心?
- 集中管理各服务配置,避免散落在代码里
- 动态更新配置,服务实时感知变动
- 简化环境切换(开发、测试、生产)
典型方案
Spring Cloud Config 是常见的配置中心技术。它支持把配置放到Git仓库,微服务启动时拉取或监听配置变化。
简单示例:Spring Cloud Config Server配置
java
package com.example.configserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
@SpringBootApplication
@EnableConfigServer // 启用配置服务
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}application.yml (配置Git仓库位置)
yaml
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: https://github.com/example/config-repo # 配置仓库地址服务启动后,会暴露配置接口,其他微服务可以通过配置客户端动态获取。
这段代码做了什么:
- 启动配置服务器,变身配置服务的中枢。
- 配置仓库地址(一般放公共配置文件)。
配置客户端示例(UserService):
yaml
spring:
application:
name: userservice
cloud:
config:
uri: http://localhost:8888 # 指向配置中心UserService启动时会从配置中心拉取配置,实现统一管理。
服务发现
如果没有硬编码地址,服务如何找到彼此?答案是“服务发现”(Service Discovery)。
服务发现原理
微服务启动时,把自己注册到服务注册中心;调用方从注册中心查询可用服务列表,然后发起调用。流行的服务注册中心有Eureka、Consul、Zookeeper等。
代码示例:使用Eureka实现服务注册与发现
- 启动Eureka Server:
java
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 // 启用Eureka服务注册中心
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}application.yml:
yaml
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false- UserService作为Eureka客户端注册
用依赖和配置连接Eureka:
yaml
spring:
application:
name: userservice
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/UserService主类用@EnableEurekaClient注解开启:
java
package com.example.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient // 注册进Eureka
public class UserServiceApplication {
public static void main(String[] args) {
SpringApplication.run(UserServiceApplication.class, args);
}
}- OrderService同理,启动时从Eureka查询UserService位置。
调用服务示例(替换之前的硬编码地址):
java
String userServiceUrl = "http://userservice/users/" + userId;使用RestTemplate或Feign客户端,Spring Cloud会自动通过Eureka解析服务名为具体实例地址。
⚠️ 常见陷阱
服务拆分过细,导致管理复杂
拆分服务虽然好,但过度拆分会让系统变成“分布式的单体”,管理调用链变得凌乱,部署压力大。建议遵循业务边界拆分,一开始不要追求极致细粒度。缺乏配置中心导致环境切换困难
硬编码配置会让测试环境和生产环境维护成本高。一定要提前规划配置中心实现动态管理。服务发现后调用失败无降级方案
没有设计熔断器和重试机制时,调用失败很可能导致系统雪崩。建议配合Hystrix或Resilience4j实现容错。
💡 实战建议
- 先用单体开发快速迭代,核心流程稳定后再拆分微服务。
- 使用配置中心统一管理环境配置,避免环境差异。
- 服务注册发现配合负载均衡,提升可用性和扩展性。
- 针对关键服务设计异步通信,减少同步调用等待。
- 加入链路追踪(如Zipkin),帮助调试分布式调用流程。
🔍 深入理解
微服务拆分和领域驱动设计(DDD)
虽然这里我们介绍了简单拆分思路,但微服务拆分的更科学方法是基于领域驱动设计,识别领域边界(Bounded Context),围绕业务能力拆分。让服务自然对应业务子域,避免功能交叉和数据耦合。
实战应用
假设你在开发一家网上书店,从单体应用迁移到微服务架构。你先将用户管理和订单处理拆成两个服务。订单服务要实时根据用户信息决定订单优惠。于是:
- 用户服务注册到Eureka
- 订单服务通过Eureka查找用户服务接口
- 两服务配置都从配置中心加载,支持一键切换测试/生产环境
经过测试你发现调用链中如果用户服务宕机,订单服务也挂了。这促使你为调用增加了熔断和异步消息机制,提升系统弹性。
小结
- 微服务通过拆分职责清晰的小服务,提升开发效率和扩展性
- 服务间通信有同步和异步两种模式,初学推荐先掌握同步调用
- 配置中心集中管理配置,实现动态环境切换
- 服务发现帮助动态定位服务实例,减少硬编码
- 实际项目中避免过度拆分和无容错设计,提升系统稳定性
希望通过这一章的学习,你对微服务的核心组成和实践流程有了立体的认识。它不是一蹴而就的,需要我们一步步摸索和调整。放心,我还会陪你一起挖掘更深的微服务秘密!
