首先思考一点这为什么是微服务的内容,微服务是每个功能拆成独立应用

服务注册

微服务架构中,每个独立的服务(比如支付服务、订单服务)启动后,会主动把自己的核心信息(服务名、IP、端口、接口路径) 上报到一个专门的 “登记中心”,这个过程就是服务注册。

关键工具

  • Zookeeper:你之前接触到的核心注册中心,是分布式的协调工具,能存储服务的注册信息,还能实时感知服务是否在线(比如某个服务挂了,Zookeeper 会立刻更新列表);
  • Nacos/Eureka/Consul:其他主流注册中心

通俗场景

就像你开了一家 “支付服务” 店铺,开业后主动去 “Zookeeper 商户名录中心” 登记:“我是支付服务,地址是 192.168.1.100:8004,大家找我付款就来这个地址”。

服务调用

微服务之间的 “相互请求” 就是服务调用 —— 比如订单服务需要调用支付服务完成付款,用户服务需要调用订单服务查询订单,这个跨服务的接口请求过程就是服务调用。

关键工具

  • 基础方式:基于 HTTP 的 RestTemplate(直接拼接 IP + 端口调用);
  • 主流方式:Feign(声明式调用,不用写复杂的 HTTP 请求,像调本地方法一样调远程服务);

结合注册中心(Zookeeper)的流程

  1. 订单服务先去 Zookeeper 查 “支付服务的地址”(这一步叫服务发现,是调用的前置);
  2. Zookeeper 返回支付服务的 IP:8004;
  3. 订单服务通过 Feign/RestTemplate 向 192.168.1.100:8004 发起请求,完成支付调用。

核心作用

实现微服务之间的协作,让拆分后的服务能共同完成业务(比如下单→支付→发货)。

服务降级

当某个服务出现问题(比如响应超时、宕机、访问量突增),为了避免整个系统崩溃,主动切断这个服务的非核心功能,或返回兜底数据,这个过程就是服务降级。

关键工具

  • Sentinel/Hystrix:主流的熔断降级工具(Sentinel 是阿里开源,更易上手)。

通俗场景

比如 “秒杀活动” 中,支付服务压力过大,此时:

  • 非核心功能(比如 “查询支付记录”)直接降级,返回 “当前高峰期,暂无法查询”;
  • 核心功能(“支付下单”)保留,但响应超时的话,返回 “支付请求已接收,稍后确认”(兜底数据);
  • 目的是让核心功能能正常运行,避免整个支付服务挂掉。

核心作用

“舍小保大”,防止单个服务故障引发整个微服务集群的雪崩(比如支付服务挂了,订单服务一直重试,导致订单服务也挂了)。

服务网关

微服务的 “统一入口”—— 所有前端请求(比如 APP、网页)都先经过网关,再由网关转发到对应的微服务,网关还能统一处理认证、限流、日志、跨域等通用功能。

关键工具

  • Spring Cloud Gateway/Spring Cloud Zuul:主流网关框架(Gateway 是新一代,性能更好)。

通俗场景

你去商场(微服务集群),不会直接冲进各个店铺(支付、订单服务),而是先经过商场大门(网关):

  • 大门先查你的会员卡(网关统一认证);
  • 告诉你 “支付服务在 3 楼 8004 号铺”(网关转发请求);
  • 如果人太多,大门会限制进入人数(网关限流);
  • 全程记录你去了哪个店铺(网关统一日志)。

核心作用

  1. 简化前端调用:前端只需要调网关的地址,不用记所有微服务的 IP + 端口;
  2. 统一处理通用功能:认证、限流、跨域等不用每个服务都写一遍;
  3. 隐藏微服务地址:提高安全性(外部无法直接访问微服务)。

服务配置

微服务的配置(比如数据库密码、端口号、Zookeeper 地址)不再写死在代码里,而是集中存储在 “配置中心”,服务启动时从配置中心拉取配置,配置变更时还能实时推送,这个过程就是服务配置。

关键工具

  • Nacos/Spring Cloud Config:Nacos 最常用(既能做注册中心,又能做配置中心)。

通俗场景

你之前的server.port:8004如果写死在代码里,想改端口就要改代码、重新打包、重新部署;如果把server.port存在 Nacos 配置中心:

  • 服务启动时自动从 Nacos 拉取 8004 这个配置;
  • 想改端口为 8005,直接在 Nacos 后台改,服务不用重启就能生效。

核心作用

解决 “配置分散、改配置要重启服务” 的问题,适合大规模微服务集群的配置统一管理。

服务总线

服务总线是微服务之间的 “消息通道”—— 用于在多个微服务之间传递配置变更、事件通知等消息,实现配置的统一刷新、服务间的异步通信。

关键工具

  • Spring Cloud Bus:主流总线框架,通常和 RabbitMQ/Kafka(消息队列)配合使用。

通俗场景

比如你有 10 个支付服务实例(都注册在 Zookeeper),现在要把它们的端口都从 8004 改成 8005:

  • 你在 Nacos 改了配置,服务总线会把 “配置变更” 这个消息,通过 RabbitMQ 发送给所有 10 个支付服务实例;
  • 所有实例收到消息后,自动刷新配置,不用逐个重启。

核心作用

  1. 实现配置的批量刷新(比如改一个配置,所有相关服务都能实时生效);
  2. 实现微服务之间的异步通信(比如订单创建后,通过总线通知库存服务扣减库存)。

problem

Maven中的DependencyManagement和Dependencies区别

在 Maven 中,DependencyManagementDependencies都是管理依赖的核心配置,但作用和场景完全不同:

1. Dependencies(直接依赖)

  • 作用实际引入依赖,会将配置的依赖下载到项目中,并参与编译、打包等构建过程。
  • 特点
    • 写在dependencies标签下的依赖,会直接生效(项目会真正引入这个 Jar 包)。
    • 子模块会继承父模块的dependencies依赖(无需重复配置)。
  • 场景:项目需要直接使用的依赖(比如 Spring Boot 的spring-boot-starter-web)。

2. DependencyManagement(依赖管理)

  • 作用统一管理依赖的版本、范围等信息,但不实际引入依赖(仅做 “声明”)。
  • 特点
    • 写在dependencyManagement标签下的依赖,不会自动下载到项目,需要在dependencies中再次声明才会生效。
    • 子模块可以继承父模块dependencyManagement中定义的依赖版本(子模块声明时无需写版本号,统一由父模块管理)。
  • 场景:多模块项目中统一管理依赖版本(避免子模块版本不一致),或提前声明可能用到的依赖。

举个例子

父模块的pom.xml

<!-- 父模块:用dependencyManagement统一管理版本 -->
<dependencyManagement>
  <<dependencies>
    <!-- 仅声明版本,不实际引入 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      <version>2.7.0</version>
    </dependency>
  </</dependencies>
</dependencyManagement>

子模块的pom.xml:

<!-- 子模块:从父模块继承版本,实际引入依赖 -->
<<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <!-- 无需写version,自动用父模块的2.7.0 -->
  </dependency>
</</dependencies>
核心区别总结

维度

Dependencies

DependencyManagement

是否实际引入依赖

✅ 是(直接下载 Jar 包)

❌ 否(仅声明信息)

子模块继承行为

✅ 子模块自动继承依赖

❌ 子模块需手动声明才会引入

核心作用

引入项目需要的依赖

统一管理依赖的版本、范围等信息

restTemplate什么作用

简单来说:RestTemplate 是 Spring 框架提供的一个同步 HTTP 客户端工具,专门用于在 Java 程序中发送 HTTP 请求(如 GET/POST/PUT/DELETE),并便捷地处理响应结果,无需手动编写繁琐的 HTTP 连接、请求参数拼接、响应解析等代码

它就像 Java 程序的 “浏览器”,帮助后端服务之间(如微服务间通信)或后端调用第三方 HTTP 接口(如调用微信支付、天气 API)时,简化 HTTP 交互流程。

一、核心作用详解

1. 简化 HTTP 请求编写,告别原生 JDBC 式繁琐代码

原生 Java 发送 HTTP 请求需要使用 HttpURLConnectionHttpClient,需要手动处理连接建立、参数拼接、流读取、异常捕获等,代码冗余且易出错。RestTemplate 封装了这些底层细节,通过简洁的 API 即可完成请求发送,大幅减少样板代码。

对比:原生 HttpClient vs RestTemplate

  • 原生 HttpClient 发送 GET 请求(繁琐):
// 需手动创建客户端、请求、处理响应,代码量大
CloseableHttpClient client = HttpClients.createDefault();
HttpGet request = new HttpGet("https://api.example.com/user/1");
CloseableHttpResponse response = client.execute(request);
// 手动读取响应流、解析数据...
  • RestTemplate 发送 GET 请求(简洁):
RestTemplate restTemplate = new RestTemplate();
// 一行代码完成请求+响应解析
User user = restTemplate.getForObject("https://api.example.com/user/1", User.class);

2. 自动完成请求 / 响应的序列化与反序列化

RestTemplate 内置了消息转换器(HttpMessageConverter),支持将 Java 对象自动转换为 JSON/XML 格式的请求体(如 POST 请求传递 JSON 参数),也能将响应的 JSON/XML 自动转换为 Java 实体类,无需手动使用 FastJSON、Jackson 等工具进行序列化操作。

示例:发送 POST 请求(自动序列化 / 反序列化)

// 1. 准备请求参数(Java 对象)
UserRequest requestParam = new UserRequest("张三", 25);
// 2. 发送 POST 请求,自动将 requestParam 转为 JSON,响应自动转为 User 对象
RestTemplate restTemplate = new RestTemplate();
User user = restTemplate.postForObject(
    "https://api.example.com/user/add",  // 请求地址
    requestParam,                        // 请求体(自动转 JSON)
    User.class                           // 响应类型(自动反序列化)
);

3. 支持多种 HTTP 请求方法,覆盖常见场景

RestTemplate 封装了 HTTP 所有常用请求方法,满足不同业务需求:

HTTP 方法

RestTemplate 对应方法

用途

GET

getForObject()

/getForEntity()

查询数据(获取资源)

POST

postForObject()

/postForEntity()

/postForLocation()

创建数据(提交资源)

PUT

put()

更新数据(全量更新)

DELETE

delete()

删除数据(删除资源)

HEAD

headForHeaders()

获取响应头信息

OPTIONS

optionsForAllow()

获取接口支持的 HTTP 方法

其中,getForEntity()/postForEntity()getForObject()/postForObject() 更强大,能获取完整的响应信息(状态码、响应头、响应体),便于处理异常场景。

4. 可配置与扩展,适配复杂场景

RestTemplate 支持自定义配置,满足特殊需求:

  • 配置请求头:设置 Token、Content-Type 等(如接口认证、指定请求格式);
  • 配置超时时间:避免请求长时间阻塞;
  • 替换消息转换器:如使用 FastJSON 替代默认的 Jackson 进行序列化;
  • 配置拦截器:统一处理日志记录、请求签名等通用逻辑。

示例:自定义配置 RestTemplate(设置超时 + 请求头)

// 1. 配置 HTTP 连接池与超时时间
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(5000);  // 连接超时 5 秒
factory.setReadTimeout(10000);    // 读取超时 10 秒

// 2. 创建 RestTemplate 实例
RestTemplate restTemplate = new RestTemplate(factory);

// 3. 统一设置请求头(如认证 Token)
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer xxxxxx");
headers.setContentType(MediaType.APPLICATION_JSON);

// 4. 发送请求
HttpEntity<UserRequest> requestEntity = new HttpEntity<>(requestParam, headers);
ResponseEntity<User> response = restTemplate.postForEntity(
    "https://api.example.com/user/add",
    requestEntity,
    User.class
);

// 获取响应状态码、响应体
if (response.getStatusCode().is2xxSuccessful()) {
    User result = response.getBody();
}
为什么说消费者只有controller,提供者才有service和dao

微服务架构中 “消费者 - 提供者” 的职责划分场景,核心逻辑是:消费者只需要调用提供者的接口,不需要关心提供者的内部实现;而提供者需要实现完整的业务逻辑和数据操作

具体解释:

  • 提供者(比如你之前的cloud-provider-payment8001:是 “服务的实现方”,需要完成业务逻辑(Service)+ 数据访问(Dao)+ 对外暴露接口(Controller)—— 因为它要自己处理业务、操作数据库,再把能力通过 Controller(比如 REST 接口)提供给外部。
  • 消费者(比如一个订单服务):是 “服务的调用方”,只需要通过 Controller(或 Feign 接口)调用提供者的接口,不需要自己写 Service 和 Dao—— 因为业务逻辑和数据操作都由提供者完成,消费者只负责发起请求、接收结果,不用重复实现底层逻辑。

举个例子:

  • 支付服务(提供者):有PaymentService处理支付逻辑,PaymentDao操作数据库,再用PaymentController暴露 “创建订单” 接口;
  • 订单服务(消费者):只需要调用支付服务的 “创建订单” 接口,自己不需要写支付相关的 Service 和 Dao,所以消费者项目里可能只有自己的 Controller(或 Feign 客户端)。

Note

  • 口诀:建module,改pom,写yaml,主启动,业务类
  • 引入依赖并配置地址,就是在注册服务
  • 消费者只有controller,提供者才有service和dao
  • 集群注册的原理是互相注册,相互守望
  • 新增了一个注解,在主启动类就要激活方法吗,平面,盘,mokads+
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐