SpringCloud02-服务拆分&远程调用

一、服务的拆分

1-1、springcloud项目的标准结构

SpringCloud 项目 ≠ 一个项目,而是一组项目(多个 SpringBoot 服务)。

这组项目通常包含:

  • 网关

  • 注册中心

  • 配置中心

  • 业务服务(如用户/订单/支付)

  • 公共依赖模块


标准项目结构:

复制代码
cloud-project/               ← 父工程(管理所有模块)
│── pom.xml                  ← 统一版本管理(dependencyManagement)
│
├── cloud-common/            ← 公共模块(工具类/统一响应/异常处理)
│   └── pom.xml
│
├── cloud-api/               ← 公共 Feign 接口模块(服务间调用用)
│   └── pom.xml
│
├── cloud-gateway/           ← 服务网关模块(统一入口)
│   └── pom.xml
│
├── cloud-register/          ← 注册中心(Nacos / Eureka)
│   └── pom.xml
│
├── cloud-config/            ← 配置中心(Nacos Config / SpringCloud Config)
│   └── pom.xml
│
├── cloud-user-service/      ← 用户服务(业务服务 A)
│   └── pom.xml
│
├── cloud-order-service/     ← 订单服务(业务服务 B)
│   └── pom.xml
│
└── cloud-pay-service/       ← 支付服务(业务服务 C)
    └── pom.xml

各模块用来干嘛?

模块 作用 你可以理解为
cloud-project(父工程) 管理所有子模块的版本和依赖 整个系统的大外框
cloud-common 公共工具类、返回结果封装、异常处理 公共工具箱
cloud-api Feign 接口、服务之间的调用客户端 服务之间的通讯协议
cloud-gateway 统一入口、权限验证、路由、限流 大门/前台
cloud-register 服务注册与发现(Nacos/Eureka) 服务通讯录
cloud-config 集中配置管理 公司制度手册
cloud-user-service 用户业务逻辑 工人 A
cloud-order-service 订单业务逻辑 工人 B
cloud-pay-service 支付业务逻辑 工人 C

1-2、项目从零启动的顺序

  1. 先启动注册中心(Nacos/Eureka)

  2. 再启动配置中心(如果有)

  3. 再启动网关

  4. 最后启动每个业务服务

为什么?

因为业务服务启动时需要去「注册中心」登记自己。

二、微服务的远程调用

2-1、DEMO项目结构

2-2、RestTemplate 发起http请求

2-3、Feign

1、微服务之间的远程调用有两种方式

调用方式 技术 特点
基于 HTTP OpenFeign(最常用) 写接口就能调用,简单优雅
基于 RPC Dubbo / gRPC / Thrift 二进制协议,性能更高,但更复杂

SpringCloud 主推的是 OpenFeign


2、场景举例

订单服务 → 想要查询用户信息 → 调用用户服务的接口

复制代码
OrderService ----(网络调用)----> UserService

3、开始用 Feign 调用

第一步:在服务中开启 Feign

在订单服务的启动类上加:

java 复制代码
@EnableFeignClients
@SpringBootApplication
public class OrderApplication {}

第二步:在 pom.xml 中引入依赖
XML 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

第三步:定义一个 Feign 接口
java 复制代码
@FeignClient(name = "user-service") // 指向注册中心里的服务名
public interface UserClient {

    @GetMapping("/user/{id}")
    UserDTO getUserById(@PathVariable("id") Long id);

}

注意:

部分 意义
@FeignClient(name="user-service") 告诉 Feign 去调用 注册中心中名字叫 user-service 的服务
@GetMapping("/user/{id}") 告诉它调用对方的这个 HTTP 接口

【注意】:

这是被调用的接口!!!


第四步:在订单服务里调用它(像本地方法一样简单)
java 复制代码
@Service
public class OrderService {

    @Autowired
    private UserClient userClient;

    public void createOrder(Long userId) {
        // 像本地方法一样,直接调用
        UserDTO user = userClient.getUserById(userId);
        System.out.println("下单用户:" + user.getName());
    }
}

虽然看起来像本地方法调用,但本质是 HTTP 远程调用。


2-4、Feign + 负载均衡

如果 user-service 启动多份实例:

复制代码
user-service:8081
user-service:8082
user-service:8083

Feign 会 自动做负载均衡,因为它与 Ribbon / LoadBalancer 集成。

你不需要写代码,SpringCloud 会帮你自动轮询调用不同实例。


2-5、Feign + 熔断(服务挂掉怎么办?)

如果用户服务挂了,为避免订单服务崩溃,你可以加 fallback:

java 复制代码
@FeignClient(name = "user-service", fallback = UserClientFallback.class)
public interface UserClient { ... }

@Component
public class UserClientFallback implements UserClient {
    public UserDTO getUserById(Long id) {
        return new UserDTO(-1L, "用户服务当前不可用");
    }
}

这叫 服务降级保护


小结

在 SpringCloud 中,微服务之间通过 OpenFeign 实现远程调用。

Feign 会根据 @FeignClient 指定的服务名,从 注册中心(Nacos/Eureka) 获取服务实例地址,并通过 HTTP 完成调用。

同时结合 Ribbon / LoadBalancer 实现负载均衡,结合 Sentinel/Hystrix 提供熔断与降级保护,避免服务雪崩。


一句话总结

OpenFeign = 写接口 → 自动发 HTTP 请求 + 自动负载均衡 + 可降级保护。


三、RestTemplate 和 Feign 是什么关系

技术 出现时间 作用 写代码体验
RestTemplate 老一辈 手写 URL,自行发 HTTP 请求 麻烦,自己组装参数
OpenFeign 新一代(推荐) 写接口就能调用,帮你自动 HTTP 请求 简单优雅

Feign 内部本质就是用 RestTemplate(或 HttpClient)发请求,只是帮你封装好了


3-1、代码演变过程

1)初级(无注册中心)

订单服务直接写死用户服务的 IP:

java 复制代码
RestTemplate rt = new RestTemplate();
rt.getForObject("http://localhost:8081/user/1", User.class);

缺点:写死了 IP + 端口,服务迁移/扩容就挂了。


2)中级(有注册中心 + 负载均衡 Ribbon)

java 复制代码
@Autowired
RestTemplate rt;

// 加上 @LoadBalanced,名字会去注册中心找
User u = rt.getForObject("http://user-service/user/1", User.class);

✔ 不再写死 IP

✔ 可以自动轮询多实例

✖ 但是 URL 写法仍然比较"硬"


3)高级(Feign)

java 复制代码
@FeignClient("user-service")
public interface UserClient {

    @GetMapping("/user/{id}")
    User getUser(@PathVariable Long id);
}

使用时:

复制代码
userClient.getUser(id);

像本地方法一样用 → 最优雅

相关推荐
q***96589 小时前
Spring Cloud Data Flow 简介
后端·spring·spring cloud
q***575011 小时前
Spring Cloud Nacos配置管理
后端·spring·spring cloud
踏浪无痕21 小时前
手写Spring事务框架:200行代码揭开@Transactional的神秘面纱( 附完整源代码)
spring boot·spring·spring cloud
踏浪无痕21 小时前
5个测试用例带你彻底理解Spring事务传播行为( 附完整源代码)
spring boot·spring·spring cloud
刘一说21 小时前
Nacos 与 Spring Cloud Alibaba 集成详解:依赖、配置、实战与避坑指南
spring boot·spring cloud·微服务·架构
i***486121 小时前
微服务生态组件之Spring Cloud LoadBalancer详解和源码分析
java·spring cloud·微服务
兔子撩架构1 天前
Dubbo 的同步服务调用
java·后端·spring cloud
N***H4861 天前
SpringCloud实战十三:Gateway之 Spring Cloud Gateway 动态路由
java·spring cloud·gateway
0***v7771 天前
SpringCloud Gateway 集成 Sentinel 详解 及实现动态监听Nacos规则配置实时更新流控规则
spring cloud·gateway·sentinel