从单体到微服务:Java程序员的第一步分布式实战

前端里的光
2025-12-21 18:00
阅读 228

大家好,我是掘金上经常写入门教程的全栈工程师。最近在带实习生的时候发现,很多同学虽然会写 Java,但一提到「微服务」就一脸懵——什么是服务拆分?为什么要用 Spring Cloud?面试官问“单体架构有什么问题”时,他们只能支支吾吾。

我当初学的时候也是一头雾水。那时候公司正从一个巨大的单体系统往微服务迁移,我连“注册中心”是啥都不知道,更别说动手搭建了。所以今天,我想用最简单的方式,带你亲手把一个单体 Java 项目改造成微服务架构。不讲大道理,只做能跑起来的代码。

这篇文章专为零基础的同学设计。只要你学过一点 Java、会用 IDEA、知道怎么运行一个 Spring Boot 项目,就能跟着做下去。


为什么我们要学微服务?

先说人话:微服务就是把一个大程序拆成多个小程序,每个小程序独立运行、独立开发、独立部署。

想象你开了一家餐厅:

  • 单体架构:你一个人负责买菜、切菜、炒菜、洗碗、收银……所有事都堆在一个“厨房”里。
  • 微服务架构:你请了厨师、服务员、收银员、清洁工,每个人各司其职,通过传菜口、对讲机协作。

当餐厅只有10个客人时,单体模式效率高;但当客人暴增到1000人,一个人肯定忙不过来,还容易出错。这时候,拆分团队(微服务)就成了必然选择。

面试题高频考点

“单体架构有哪些缺点?”
标准答案:

  • 随着业务增长,代码越来越臃肿,编译慢、启动慢
  • 一个模块出问题可能拖垮整个系统
  • 技术栈被锁定,难以引入新技术
  • 团队协作困难,多人改同一个代码库容易冲突

环境准备:5分钟搭好开发环境

我们要用到以下工具(全部免费):

工具 版本要求 作用
JDK 17 或 21 Java 运行环境
Maven 3.8+ 项目依赖管理
IntelliJ IDEA 最新版 开发 IDE
Spring Boot 3.x 快速构建 Java 应用
Spring Cloud 2023.x 微服务全家桶

步骤 1:安装 JDK 和 Maven

  • Oracle 官网Adoptium 下载 JDK 17
  • 配置环境变量 JAVA_HOME
  • 验证:终端输入 java -versionmvn -v

步骤 2:创建第一个 Spring Boot 项目

打开 IDEA → New Project → 选择 Spring Initializr

填写:

  • Project SDK: JDK 17
  • Language: Java
  • Spring Boot: 3.2.x
  • Dependencies: Spring Web, Spring Boot DevTools

点击 Next,项目名为 user-service,包名 com.example.userservice


核心概念:微服务三大件

微服务不是魔法,它靠三个核心组件协同工作:

  1. 服务注册与发现(比如 Eureka / Nacos)
    → 所有服务启动后要“报到”,其他服务才能找到它

  2. 服务调用(比如 OpenFeign / RestTemplate)
    → A 服务怎么调用 B 服务的接口

  3. 配置中心(比如 Nacos Config / Apollo)
    → 统一管理所有服务的配置文件

📌 小贴士:我们这次用 Nacos,因为它同时支持注册中心 + 配置中心,国内用得最多!


实战:把单体用户系统拆成两个微服务

假设我们原来有个单体项目,包含用户管理和订单功能。现在要拆成:

  • user-service:提供用户信息查询
  • order-service:提供订单创建,需要调用 user-service 获取用户姓名

第一步:启动 Nacos 服务

  1. Nacos GitHub Releases 下载最新版(如 nacos-server-2.3.0.zip)
  2. 解压后进入 bin 目录
  3. Windows 双击 startup.cmd,Mac/Linux 执行 sh startup.sh -m standalone
  4. 浏览器访问 http://localhost:8848/nacos,账号密码都是 nacos

✅ 成功标志:看到 Nacos 控制台首页

第二步:改造 user-service(服务提供者)

  1. pom.xml 添加 Nacos 依赖:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>2022.0.0.0</version>
</dependency>
  1. 修改 application.yml
server:
  port: 8081

spring:
  application:
    name: user-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
  1. 创建用户实体和控制器:
// User.java
public class User {
    private Long id;
    private String name;
    // 构造函数、getter/setter 省略
}

// UserController.java
@RestController
@RequestMapping("/user")
public class UserController {
    
    @GetMapping("/{id}")
    public User getUser(@PathVariable Long id) {
        // 模拟数据库查询
        return new User(id, "张三");
    }
}
  1. 启动 UserApplication,刷新 Nacos 控制台 → 你会看到 user-service 出现在服务列表!

第三步:创建 order-service(服务消费者)

新建一个 Spring Boot 项目,名为 order-service,同样添加 Nacos 依赖,配置 application.yml

server:
  port: 8082

spring:
  application:
    name: order-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848

然后添加 OpenFeign 依赖(用于服务间调用):

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

开启 Feign:

// OrderApplication.java
@SpringBootApplication
@EnableFeignClients
public class OrderApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderApplication.class, args);
    }
}

定义 Feign 接口:

// UserClient.java
@FeignClient(name = "user-service")
public interface UserClient {
    @GetMapping("/user/{id}")
    User getUser(@PathVariable("id") Long id);
}

创建订单逻辑:

// OrderController.java
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private UserClient userClient;

    @PostMapping("/create")
    public String createOrder(@RequestParam Long userId) {
        User user = userClient.getUser(userId);
        return "为用户 [" + user.getName() + "] 创建了订单!";
    }
}

第四步:测试端到端调用

  1. 启动 user-service
  2. 启动 order-service
  3. 调用订单接口:
    curl -X POST "http://localhost:8082/order/create?userId=1"
    
  4. 返回结果:为用户 [张三] 创建了订单!

🎉 恭喜!你已经完成了第一个微服务调用!


新手常见问题 & 避坑指南

❌ 问题1:启动报错 No qualifying bean of type 'UserClient'

原因:忘记加 @EnableFeignClients 注解。

解决:在主启动类加上该注解。


❌ 问题2:order-service 找不到 user-service

排查步骤

  1. 检查两个服务是否都注册到了 Nacos(看控制台)
  2. 检查 @FeignClient(name = "xxx") 中的 xxx 是否和 spring.application.name 完全一致
  3. 确保两个服务的 Spring Boot 和 Spring Cloud 版本兼容(推荐用 Spring Boot 3.2 + Spring Cloud 2023.0.0)

❌ 问题3:中文乱码

现象:返回 "为用户 [张三] 创建了订单!"

解决:在 Feign 接口中指定编码:

@FeignClient(name = "user-service")
public interface UserClient {
    @GetMapping(value = "/user/{id}", produces = "application/json; charset=utf-8")
    User getUser(@PathVariable("id") Long id);
}

或者全局配置:

spring:
  http:
    encoding:
      charset: UTF-8
      enabled: true

⚠️ 避坑提醒:不要过早拆分!

很多新手一学微服务就想把所有功能拆成10个服务,结果维护成本爆炸。记住:

单体架构不是原罪,过度工程才是。

建议:

  • 初期用单体 + 模块化(如 user-module、order-module)
  • 当团队超过10人、部署频率高、技术栈需要多样化时,再考虑微服务
  • 拆分原则:按业务边界,而不是按技术层(比如不要拆出一个“common-service”)

面试题延伸:微服务真的万能吗?

当然不是!面试官常问:

“微服务有哪些挑战?”

你可以这样答:

挑战 解决方案
分布式事务 使用 Saga 模式、TCC、或最终一致性
服务雪崩 熔断(Hystrix/Sentinel)、限流
日志分散 ELK / Loki 收集日志
链路追踪难 SkyWalking / Zipkin
配置混乱 Nacos Config / Apollo

💡 提示:如果你能在回答中提到“CAP 理论”或“BASE 理论”,加分!


下一步学习建议

你已经迈出了关键一步!接下来可以:

  1. 深入 Nacos:学习配置中心、集群部署
  2. 加入网关:用 Spring Cloud Gateway 做统一入口
  3. 实现熔断:集成 Sentinel 防止级联失败
  4. 链路追踪:接入 SkyWalking 查看调用链
  5. 容器化:用 Docker 打包服务,用 Kubernetes 编排

📚 推荐资源:

  • 官方文档:Spring Cloud Alibaba
  • 书籍:《微服务架构设计模式》
  • 视频:B站“狂神说微服务”系列

写在最后

微服务不是银弹,但它确实是现代 Java 后端开发的必备技能。我见过太多同学死记硬背“Eureka 是注册中心”,却没亲手跑过一行代码。今天这个小项目虽然简单,但它包含了微服务最核心的协作逻辑。

真正的理解,来自于亲手敲下的每一行代码。

下次面试官再问:“你们项目怎么做的服务拆分?” 你就可以自信地说:“我从单体开始,一步步拆出了用户服务和订单服务,并用 Nacos 实现了注册发现……”

加油!你离成为真正的后端工程师,又近了一步。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝