从零到一搭建SpringCloud微服务,一场代码世界的“分家”大戏

简介: 没有最好的架构,只有最合适的架构。微服务不是终点,而是你架构演化路上的一个里程碑。创建第一个微服务,记得先从小处着手,毕竟,罗马不是一天建成的,微服务也不是一次拆完的!

大家好,我是小悟。

第一部分:微服务是什么?一场“分家过日子”的哲学

你开了一家超级火爆的“程序猿餐厅”,一开始所有菜都在一个大厨房做:

  • 单体架构:一个厨子(服务器)包揽所有菜,点单、炒菜、煲汤、洗碗全管
  • 客人点个蛋炒饭,整个厨房都得动起来
  • 想升级蛋炒饭配方?得关店装修(停机部署)
  • 厨子感冒了?全店停业(单点故障)

微服务就像把大厨房拆了

  • 蛋炒饭部、火锅部、奶茶部各自独立
  • 每个部门有自己的小厨房(服务实例)
  • 通过传菜机器人(服务通信)协作
  • 奶茶部炸了?没事,蛋炒饭照常供应(故障隔离)

第二部分:开干!八步搭建SpringCloud全家桶

先拜码头(环境准备)

# 必备三件套
Java 11+(别用Java 8了,它都退休了)
Maven 3.6+(Java界的包工头)
IDE(IntelliJ IDEA - 程序员的法拉利)

第1步:创建父工程 - 家族的“族谱”

<!-- pom.xml - 家族总章程 -->
<?xml version="1.0" encoding="UTF-8"?>
<project>
    <modelVersion>4.0.0</modelVersion>
    
    <groupId>com.coder.micro</groupId>
    <artifactId>micro-family</artifactId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    
    <!-- 声明SpringCloud版本 - 家族用的家规版本 -->
    <properties>
        <spring.cloud.version>2021.0.3</spring.cloud.version>
        <spring.boot.version>2.7.14</spring.boot.version>
    </properties>
    
    <!-- 依赖管理 - 所有子孙该用什么版本 -->
    <dependencyManagement>
        <dependencies>
            <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>
    
    <modules>
        <module>eureka-server</module>
        <module>gateway</module>
        <module>order-service</module>
        <module>user-service</module>
    </modules>
</project>

第2步:Eureka服务注册中心 - 家族的“户口本”

# 想象成家族微信群:
# 谁在(服务上线)@所有人
# 谁睡了(服务下线)改备注
# 谁失联了(心跳检测)踢出群
// EurekaServerApplication.java - 户口本管理员
@SpringBootApplication
@EnableEurekaServer  // 开启户口本功能
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
// application.yml - 户口本配置
server:
  port: 8761  # 户口本办公室门牌号
eureka:
  client:
    register-with-eureka: false  # 户口本不用自己登记自己
    fetch-registry: false  # 不用拉取别人的信息
  server:
    eviction-interval-timer-in-ms: 30000  # 30秒检查一次谁失联了

第3步:API网关 - 家族的“前台小姐姐”

// GatewayApplication.java
@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}
// Gateway配置 - 前台路由规则
spring:
  cloud:
    gateway:
      routes:
        - id: order-service  # 找点单部的路
          uri: lb://ORDER-SERVICE  # lb=负载均衡,像电梯分流入流
          predicates:
            - Path=/api/orders/**  # 所有/orders开头的请求
            
        - id: user-service  # 找会员部的路
          uri: lb://USER-SERVICE
          predicates:
            - Path=/api/users/**
            
        # 全局过滤器 - 前台的小本本
      default-filters:
        - AddRequestHeader=X-Request-From, gateway  # 给每个请求盖个章

第4步:订单服务 - 家族的“点单部”

// OrderServiceApplication.java
@SpringBootApplication
@EnableEurekaClient  // 大喊一声:我上线了!
@EnableFeignClients  // 开启“打电话”功能
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}
// OrderController.java - 点单部接待处
@RestController
@RequestMapping("/orders")
@Slf4j
public class OrderController {
    
    @Autowired
    private UserServiceClient userServiceClient;  // 用户部的联系电话
    
    @PostMapping
    public OrderDTO createOrder(@RequestBody OrderRequest request) {
        log.info("接到新订单:{}", request);
        
        // 打个电话问用户部:这人是不是VIP?
        UserDTO user = userServiceClient.getUser(request.getUserId());
        
        if (user.isVip()) {
            log.info("VIP用户,加急处理!");
            return processVipOrder(request);
        }
        
        return processNormalOrder(request);
    }
    
    // 假装这里有很多业务逻辑...
    private OrderDTO processVipOrder(OrderRequest request) {
        return OrderDTO.builder()
                .orderId(UUID.randomUUID().toString())
                .status("VIP_优先处理")
                .message("老板,您的订单已插队!")
                .build();
    }
}

第5步:用户服务 - 家族的“会员部”

// UserController.java
@RestController
@RequestMapping("/users")
@Slf4j
public class UserController {
    
    // 用户部的VIP名单
    private Map<String, UserDTO> userDatabase = new HashMap<>();
    
    @PostConstruct
    public void init() {
        userDatabase.put("1001", new UserDTO("1001", "张大款", true));
        userDatabase.put("1002", new UserDTO("1002", "李铁柱", false));
    }
    
    @GetMapping("/{userId}")
    public UserDTO getUser(@PathVariable String userId) {
        log.info("查询用户:{}", userId);
        
        // 模拟网络延迟
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        return userDatabase.getOrDefault(userId, 
                new UserDTO(userId, "未知用户", false));
    }
}

第6步:服务间通信 - 家族的“内部电话系统”

// UserServiceClient.java - 订单部用来呼叫用户部的电话
@FeignClient(name = "USER-SERVICE")  // 声明要呼叫的服务名
public interface UserServiceClient {
    
    @GetMapping("/users/{userId}")  // 电话号码和拨号方式
    UserDTO getUser(@PathVariable String userId);
    
    // 这就是SpringCloud的魔法:
    // 看起来像本地调用,实际上是HTTP请求
    // 像极了微信语音,看似在身边,实际可能隔了个太平洋
}

第7步:配置中心 - 家族的“公告栏”

// 每个服务都要有这个配置
spring:
  config:
    import: optional:configserver:http://localhost:8888  # 看公告栏地址
  cloud:
    config:
      fail-fast: false  # 公告栏坏了也不影响营业
      
# 公告栏上写着:
# order-service.yml:
#   优惠活动:双十一打五折
#   超时时间:30秒
#   
# user-service.yml:
#   VIP门槛:消费满10000
#   签到积分:10分/天

第8步:熔断降级 - 家族的“应急方案”

// OrderService中调用用户服务时
@FeignClient(name = "USER-SERVICE", 
             fallback = UserServiceFallback.class)  // 备胎方案
public interface UserServiceClient {
    // ...
}
// 用户部失联时的备胎方案
@Component
@Slf4j
public class UserServiceFallback implements UserServiceClient {
    
    @Override
    public UserDTO getUser(String userId) {
        log.warn("用户服务失联,启用默认用户信息");
        
        // 返回兜底数据,保证订单服务不崩溃
        return UserDTO.builder()
                .userId(userId)
                .username("默认用户")
                .vip(false)
                .fromFallback(true)  // 标记这是备胎数据
                .build();
    }
}

第三部分:启动全家桶的“开机仪式”

# 启动顺序很重要,像玩多米诺骨牌:
1. 启动户口本(Eureka Server)
   cd eureka-server && mvn spring-boot:run
   # 访问 http://localhost:8761 看谁在线
2. 启动会员部(User Service)
   cd user-service && mvn spring-boot:run
   # 在Eureka页面应该能看到USER-SERVICE
3. 启动点单部(Order Service)
   cd order-service && mvn spring-boot:run
4. 启动前台(Gateway)
   cd gateway && mvn spring-boot:run
# 测试一下:
curl http://localhost:8080/api/orders \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"userId": "1001", "productId": "P001"}'
  
# 应该返回:VIP订单已插队!

第四部分:微服务开发的“生存法则”

1. 服务拆分原则 - “分家不分心”

// 好的拆分:按业务能力
- 订单服务:管下单、支付、退款
- 库存服务:管商品库存
- 物流服务:管配送
// 坏的拆分:按技术层
- Controller服务:只放Controller  // 别这么干!
- Service服务:只放Service      // 这是给自己挖坑!
- DAO服务:只放DAO            // 你会哭的!

2. 数据库设计 - “各管各的账”

-- 订单服务有自己的订单表
CREATE TABLE orders (
    id VARCHAR(32) PRIMARY KEY,
    user_id VARCHAR(32),  -- 只存用户ID,不存用户详情
    amount DECIMAL(10, 2)
    -- 不在这里创建user表的外键!这是微服务大忌!
);
-- 用户服务有自己的用户表
CREATE TABLE users (
    id VARCHAR(32) PRIMARY KEY,
    name VARCHAR(100),
    vip_level INT
    -- 不知道订单表的存在,各过各的
);

3. 分布式事务 - “家族的信任危机”

// 使用Seata处理分布式事务
@GlobalTransactional  // 分布式事务注解
public void placeOrder(OrderRequest request) {
    // 1. 扣库存(调用库存服务)
    inventoryService.reduceStock(request.getProductId());
    
    // 2. 创建订单
    orderService.createOrder(request);
    
    // 3. 扣款(调用支付服务)
    paymentService.deductBalance(request.getUserId());
    
    // 任何一步失败,所有操作都会回滚
    // 像极了"要么全部成功,要么全部撤销"
}

总结:微服务之路的苦与乐

你得到的“超能力”:

  1. 独立部署:改个按钮颜色不用重启整个系统
  2. 技术异构:订单用Java,推荐用Python,数据分析用Go
  3. 弹性伸缩:双十一给订单服务多加10台机器
  4. 容错性:推荐服务挂了?商品详情页照样能打开

你面临的“挑战”:

  1. 分布式debug:找bug像侦探破案,线索分布在5个服务里
  2. 网络延迟:本地方法调用1ms,服务间调用可能100ms
  3. 数据一致性:用户余额减少了,订单却没创建成功?
  4. 运维复杂度:原来管1个应用,现在要管20个服务

最后:

微服务不是银弹,是银制餐具

  • 适合大型团队(各自做饭不打架)
  • 适合快速迭代(各部分独立升级)
  • 适合复杂系统(分而治之)

但如果你只是开个煎饼摊

  • 一个平锅(单体应用)够了
  • 非要搞5个小灶(微服务)?
  • 光协调哪个摊鸡蛋哪个撒葱花就够你受的

微服务解决的是”人”的问题,不是”技术”的问题。当团队大到需要分山头、业务复杂到需要分领域时,才是微服务登场的最佳时机。否则,你就是用导弹打蚊子——效果震撼,但真的没必要!


代码世界的真理:没有最好的架构,只有最合适的架构。微服务不是终点,而是你架构演化路上的一个里程碑。创建第一个微服务,记得先从小处着手,毕竟,罗马不是一天建成的,微服务也不是一次拆完的!

从零到一搭建SpringCloud微服务,一场代码世界的“分家”大戏.png

谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。


您的一键三连,是我更新的最大动力,谢谢

山水有相逢,来日皆可期,谢谢阅读,我们再会

我手中的金箍棒,上能通天,下能探海

相关文章
|
4月前
|
Java 关系型数据库 Docker
Docker + Spring Boot:天生一对的完美部署
使用Docker部署Spring Boot项目能极大简化环境配置和应用分发。要将Spring Boot项目部署到Docker,主要流程是:准备项目、创建Docker镜像、运行Docker容器。
292 0
|
Java Maven 微服务
搭建springcloud项目——简单明了(一)
本文讲解搭建springcloud项目的方法:操作和eureka-user
7556 1
搭建springcloud项目——简单明了(一)
|
19天前
|
弹性计算
回放 | 阿里云OpenClaw虾友会开放麦-北京站
3月13日晚上7点,弹性计算首场OpenClaw活动——阿里云OpenClaw虾友开放麦在北京朝阳科技园C区顺利落地。活动以轻松的开放麦形式,在周五晚上为用户打造了一个轻松畅聊“云端养虾”心得的机会。
|
20天前
|
JSON 监控 搜索推荐
SpringBoot 整合 ElasticSearch,给搜索插上“光速翅膀”
SpringBoot整合ElasticSearch,就像给程序装上了“谷歌大脑”,存得多、找得快、查得准。虽然配置过程像在组装乐高,偶尔会找不到零件,但一旦搭建完成,你就能享受到“秒级搜索”的快感。
123 1
|
16天前
|
人工智能 JavaScript Docker
阿里龙虾组合来了:HiClaw + CoPaw,内存占用大幅降低
HiClaw 1.0.4 正式发布!新增轻量级 CoPaw Worker,内存仅约150MB(为OpenClaw的1/5),支持Docker与本地双模式——既省资源,又可直连浏览器、文件系统。通过统一Matrix协议,大幅降低Agent接入门槛,实现“一次接入,多端可用”。
阿里龙虾组合来了:HiClaw + CoPaw,内存占用大幅降低
|
2月前
|
人工智能 自然语言处理 机器人
2026年OpenClaw(Clawdbot)接入QQ机器人阿里云官方保姆级教程
在2026年AI自动化办公与即时通讯协同需求持续攀升的当下,OpenClaw(原Clawdbot、曾用名Moltbot)凭借“自然语言驱动、全场景任务自动化、多终端无缝适配”的核心优势,成为个人办公提效、轻量团队协同、社群管理的优选AI工具。作为GitHub星标量超19万的开源AI自动化代理平台,它打破了传统AI仅能对话的局限,真正实现“能听指令、能做实事”——无论是文档生成、日程提醒、文件整理,还是联网搜索、简单代码开发、跨工具协同,只需一句口语化指令,就能自动完成全流程操作,无需手动干预。其开源特性更支持用户根据需求灵活扩展功能,适配多样化使用场景,完美贴合现代办公与社群运营的高效需求。
3870 1
|
负载均衡 Java Nacos
Spring Cloud五大组件
Spring Cloud五大组件
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
1854 70
从单体到微服务:如何借助 Spring Cloud 实现架构转型