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);

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

相关推荐
wno7045 小时前
Spring Cloud Hystrix Dashboard仪表盘
spring·spring cloud·hystrix
BUG指挥官8 小时前
Redis已接入AI
数据库·人工智能·spring boot·redis·spring cloud
wno70419 小时前
Spring Cloud Hystrix服务容错
spring·spring cloud·hystrix
苏渡苇1 天前
Spring Insight 里上报 Span 为什么用 JDK HttpClient 而不是 RestTemplate
java·后端·spring·spring cloud·springboot·性能监控
YOU OU2 天前
Spring Cloud Consul
spring cloud·consul·java-consul
重生之我是Java开发战士2 天前
【Spring Cloud】Eureka服务注册发现与LoadBalancer负载均衡
spring cloud·eureka·负载均衡
谢亮_vipxieliang2 天前
ValidX vs Google Guava Preconditions:验证 vs 断言
java·spring boot·后端·spring cloud·hibernate·guava
夏天拐跑了西瓜3 天前
Spring Cloud 微服务实战(八):Hystrix熔断降级——从服务雪崩到断路器模式
spring cloud·hystrix·微服务
重生之我是Java开发战士4 天前
【Spring Cloud】认识微服务与工程搭建
spring·spring cloud·微服务
墨着染霜华5 天前
SpringCloud Gateway线上Nginx代理后自定义下划线请求头丢失(app_name/app_version获取不到)完美解决
nginx·spring cloud·gateway