PageSourceSearch

https://weiruyi.github.io/assets/%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86…E7%A8%8B%E8%B0%83%E7%94%A8.html-WTPstYaI.js

js weiruyi.github.io collected 2026-10-03 10:10:49 UTC 61,045 bytes, 154 lines download raw bytes

1import{_ as s}from"./plugin-vue_export-helper-DlAUqK2U.js";import{r as a,c as t,a as e,f as p,b as c,w as o,d as l,o as i,e as u}from"./app-CpE2Mp5p.js";const d="/image/cloud/cloud1.jpg",r="/image/cloud/cloud1.png",k="/image/cloud/cloud2.jpg",m="/image/cloud/cloud2.png",g={},v=l(`<h1 id="服务注册与远程调用" tabindex="-1"><a class="header-anchor" href="#服务注册与远程调用"><span>服务注册与远程调用</span></a></h1><h2 id="一、介绍" tabindex="-1"><a class="header-anchor" href="#一、介绍"><span>一、介绍</span></a></h2><p>在拆分黑马商城的时候,我们发现一个问题:就是购物车业务中需要查询商品信息,但商品信息查询的逻辑全部迁移到了<code>item-service</code>服务,导致我们无法查询。</p><p>最终结果就是查询到的购物车数据不完整,因此要想解决这个问题,我们就必须改造其中的代码,把原本本地方法调用,改造成跨微服务的远程调用(RPC,即<strong>R</strong>emote <strong>P</strong>roduce <strong>C</strong>all)。</p><p>那么问题来了:我们该如何跨服务调用,准确的说,如何在<code>cart-service</code>中获取<code>item-service</code>服务中的提供的商品数据呢?</p><p>大家思考一下,我们以前有没有实现过类似的远程查询的功能呢?</p><p>答案是肯定的,我们前端向服务端查询数据,其实就是从浏览器远程查询服务端数据。比如我们刚才通过Swagger测试商品查询接口,就是向<code>http://localhost:8081/items</code>这个接口发起的请求:</p><h3 id="_1、resttemplate" tabindex="-1"><a class="header-anchor" href="#_1、resttemplate"><span>1、RestTemplate</span></a></h3><p>Spring给我们提供了一个RestTemplate的API,可以方便的实现Http请求的发送。</p><div class="hint-container info"><p class="hint-container-title">RestTemplate使用的基本步骤如下</p><ul><li>注册RestTemplate到Spring容器</li><li>调用RestTemplate的API发送请求,常见方法有: <ul><li>getForObject:发送Get请求并返回指定类型对象</li><li>PostForObject:发送Post请求并返回指定类型对象</li><li>put:发送PUT请求</li><li>delete:发送Delete请求</li><li>exchange:发送任意类型请求,返回ResponseEntity</li></ul></li></ul></div><p>先将RestTemplate注册为一个Bean:</p><div class="language-java line-numbers-mode" data-ext="java" data-title="java"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>hmall<span class="token punctuation">.</span>cart<span class="token punctuation">.</span>config</span><span class="token punctuation">;</span>
2
3<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Bean</span></span><span class="token punctuation">;</span>
4<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Configuration</span></span><span class="token punctuation">;</span>
5<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>client<span class="token punctuation">.</span></span><span class="token class-name">RestTemplate</span></span><span class="token punctuation">;</span>
6
7<span class="token annotation punctuation">@Configuration</span>
8<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">RemoteCallConfig</span> <span class="token punctuation">{</span>
9
10    <span class="token annotation punctuation">@Bean</span>
11    <span class="token keyword">public</span> <span class="token class-name">RestTemplate</span> <span class="token function">restTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
12        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">RestTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
13    <span class="token punctuation">}</span>
14<span class="token punctuation">}</span>
15</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h3 id="_2、远程调用" tabindex="-1"><a class="header-anchor" href="#_2、远程调用"><span>2、远程调用</span></a></h3><p>接下来,我们修改<code>cart-service</code>中的<code>com.hmall.cart.service.impl.\`\`CartServiceImpl</code>的<code>handleCartItems</code>方法,发送http请求到<code>item-service</code>:</p><div class="language-java line-numbers-mode" data-ext="java" data-title="java"><pre class="language-java"><code>        <span class="token comment">// List&lt;ItemDTO&gt; items = itemService.queryItemByIds(itemIds);</span>
16		<span class="token comment">//1、利用restTemplate 发起HTTP请求,得到HTTP响应</span>
17        <span class="token class-name">ResponseEntity</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">ItemDTO</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> response <span class="token operator">=</span> restTemplate<span class="token punctuation">.</span><span class="token function">exchange</span><span class="token punctuation">(</span>
18                <span class="token string">&quot;http://192.168.175.129:8081/items?ids={ids}&quot;</span><span class="token punctuation">,</span>  <span class="token comment">//请求路径</span>
19                <span class="token class-name">HttpMethod</span><span class="token punctuation">.</span><span class="token constant">GET</span><span class="token punctuation">,</span>  <span class="token comment">//请求方法</span>
20                <span class="token keyword">null</span><span class="token punctuation">,</span>  <span class="token comment">//请求实体</span>
21                <span class="token keyword">new</span> <span class="token class-name">ParameterizedTypeReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">ItemDTO</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token comment">//返回值类型</span>
22                <span class="token class-name">Map</span><span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span><span class="token string">&quot;ids&quot;</span><span class="token punctuation">,</span> <span class="token class-name">CollUtils</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>itemIds<span class="token punctuation">,</span> <span class="token string">&quot;,&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span>   <span class="token comment">//请求参数</span>
23        <span class="token punctuation">)</span><span class="token punctuation">;</span>
24        <span class="token comment">//2、解析响应</span>
25        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>response<span class="token punctuation">.</span><span class="token function">getStatusCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is2xxSuccessful</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
26            <span class="token keyword">return</span><span class="token punctuation">;</span>
27        <span class="token punctuation">}</span>
28        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ItemDTO</span><span class="token punctuation">&gt;</span></span> items <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">getBody</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
29</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>可以看到,利用RestTemplate发送http请求与前端ajax发送请求非常相似,都包含四部分信息:</p><ul><li><p>请求方式</p></li><li><p>请求路径</p></li><li><p>请求参数</p></li><li><p>返回值类型</p></li></ul><h3 id="_3、缺点" tabindex="-1"><a class="header-anchor" href="#_3、缺点"><span>3、缺点</span></a></h3><p>假如商品微服务被调用较多,为了应对更高的并发,我们进行了多实例部署此时,每个<code>item-service</code>的实例其IP或端口不同,问题来了:</p><ul><li>item-service这么多实例,cart-service如何知道每一个实例的地址?</li><li>http请求要写url地址,<code>cart-service</code>服务到底该调用哪个实例呢?</li><li>如果在运行过程中,某一个<code>item-service</code>实例宕机,<code>cart-service</code>依然在调用该怎么办?</li><li>如果并发太高,<code>item-service</code>临时多部署了N台实例,<code>cart-service</code>如何知道新实例的地址?</li></ul><p>为了解决上述问题,就必须引入注册中心的概念了</p><h2 id="二、服务注册-nacos" tabindex="-1"><a class="header-anchor" href="#二、服务注册-nacos"><span>二、服务注册(Nacos)</span></a></h2><h3 id="_1、注册中心原理" tabindex="-1"><a class="header-anchor" href="#_1、注册中心原理"><span>1、注册中心原理</span></a></h3><p>在微服务远程调用的过程中,包括两个角色:</p><ul><li>服务提供者:提供接口供其它微服务访问,比如<code>item-service</code></li><li>服务消费者:调用其它微服务提供的接口,比如<code>cart-service</code></li></ul><p>在大型微服务项目中,服务提供者的数量会非常多,为了管理这些服务就引入了<strong>注册中心</strong>的概念。注册中心、服务提供者、服务消费者三者间关系如下:</p><figure><img src="`+d+'" alt="" tabindex="0" loading="lazy"><figcaption></figcaption></figure><div class="hint-container tip"><p class="hint-container-title">流程如下</p><ol><li><p>服务启动时就会注册自己的服务信息(服务名、IP、端口)到注册中心</p></li><li><p>调用者可以从注册中心订阅想要的服务,获取服务对应的实例列表(1个服务可能多实例部署)</p></li><li><p>调用者自己对实例列表负载均衡,挑选一个实例</p></li><li><p>调用者向该实例发起远程调用</p></li></ol></div><p>当服务提供者的实例宕机或者启动新实例时,调用者如何得知呢?</p><ul><li>服务提供者会定期向注册中心发送请求,报告自己的健康状态(心跳请求)</li><li>当注册中心长时间收不到提供者的心跳时,会认为该实例宕机,将其从服务的实例列表中剔除</li><li>当服务有新实例启动时,会发送注册服务请求,其信息会被记录在注册中心的服务实例列表</li><li>当注册中心服务列表变更时,会主动通知微服务,更新本地服务列表</li></ul><h3 id="_2、nacos注册中心" tabindex="-1"><a class="header-anchor" href="#_2、nacos注册中心"><span>2、Nacos注册中心</span></a></h3><div class="hint-container info"><p class="hint-container-title">目前开源的注册中心框架有很多,国内比较常见的有</p><ul><li>Eureka:Netflix公司出品,目前被集成在SpringCloud当中,一般用于Java应用</li><li>Nacos:Alibaba公司出品,目前被集成在SpringCloudAlibaba中,一般用于Java应用</li><li>Consul:HashiCorp公司出品,目前集成在SpringCloud中,不限制微服务语言</li></ul></div><p><strong>1)配置MySQL</strong></p><p>我们基于Docker来部署Nacos的注册中心,首先我们要准备MySQL数据库表,用来存储Nacos的数据,mysql脚本可以从github下载</p><p><a href="https://github.com/alibaba/nacos/tree/develop/distribution/conf" target="_blank" rel="noopener noreferrer">下载地址</a></p><figure><img src="'+r+`" alt="" tabindex="0" loading="lazy"><figcaption></figcaption></figure><p><strong>2)修改配置文件</strong></p><p>创建一个<code>nacos/custom.env</code>文件,MYSQL_SERVICE_HOST也就是mysql地址,需要修改为你自己的虚拟机IP地址:</p><div class="language-text line-numbers-mode" data-ext="text" data-title="text"><pre class="language-text"><code>PREFER_HOST_MODE=hostname
30MODE=standalone
31SPRING_DATASOURCE_PLATFORM=mysql
32MYSQL_SERVICE_HOST=192.168.175.129
33MYSQL_SERVICE_DB_NAME=nacos
34MYSQL_SERVICE_PORT=3306
35MYSQL_SERVICE_USER=root
36MYSQL_SERVICE_PASSWORD=123
37MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&amp;connectTimeout=1000&amp;socketTimeout=3000&amp;autoReconnect=true&amp;useSSL=false&amp;allowPublicKeyRetrieval=true&amp;serverTimezone=Asia/Shanghai
38</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>3)创建镜像</strong></p><p>然后,将刚刚创建的的<code>nacos</code>目录上传至虚拟机的<code>/root</code>
38目录。进入root目录,然后执行下面的docker命令:</p><div class="language-bash line-numbers-mode" data-ext="sh" data-title="sh"><pre class="language-bash"><code><span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token punctuation">\\</span>
39<span class="token parameter variable">--name</span> nacos <span class="token punctuation">\\</span>
40--env-file ./nacos/custom.env <span class="token punctuation">\\</span>
41<span class="token parameter variable">-p</span> <span class="token number">8848</span>:8848 <span class="token punctuation">\\</span>
42<span class="token parameter variable">-p</span> <span class="token number">9848</span>:9848 <span class="token punctuation">\\</span>
43<span class="token parameter variable">-p</span> <span class="token number">9849</span>:9849 <span class="token punctuation">\\</span>
44<span class="token parameter variable">--restart</span><span class="token operator">=</span>always <span class="token punctuation">\\</span>
45nacos/nacos-server:v2.1.0-slim
46</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>启动完成后,访问下面地址:http://192.168.175.129:8848/nacos/,注意将<code>192.168.175.129</code>替换为你自己的虚拟机IP地址。</p><p>首次访问会跳转到登录页,<strong>账号密码都是nacos</strong></p><h3 id="_3、服务注册" tabindex="-1"><a class="header-anchor" href="#_3、服务注册"><span>3、服务注册</span></a></h3><p>接下来,我们把<code>item-service</code>注册到Nacos</p><div class="hint-container info"><p class="hint-container-title">步骤如下:</p><ul><li>引入依赖</li><li>配置Nacos地址</li><li>重启</li></ul></div><p><strong>1)添加依赖</strong></p><p>在<code>item-service</code>的<code>pom.xml</code>中添加依赖:</p><div class="language-xml line-numbers-mode" data-ext="xml" data-title="xml"><pre class="language-xml"><code><span class="token comment">&lt;!--nacos 服务注册发现--&gt;</span>
47<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
48    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>com.alibaba.cloud<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
49    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-cloud-starter-alibaba-nacos-discovery<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
50<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
51</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>2)配置Nacos</strong></p><p>在<code>item-service</code>的<code>application.yml</code>中添加nacos地址配置:</p><div class="language-yaml line-numbers-mode" data-ext="yml" data-title="yml"><pre class="language-yaml"><code><span class="token key atrule">spring</span><span class="token punctuation">:</span>
52  <span class="token key atrule">application</span><span class="token punctuation">:</span>
53    <span class="token key atrule">name</span><span class="token punctuation">:</span> item<span class="token punctuation">-</span>service <span class="token comment"># 服务名称</span>
54  <span class="token key atrule">cloud</span><span class="token punctuation">:</span>
55    <span class="token key atrule">nacos</span><span class="token punctuation">:</span>
56      <span class="token key atrule">server-addr</span><span class="token punctuation">:</span> 192.168.150.101<span class="token punctuation">:</span><span class="token number">8848</span> <span class="token comment"># nacos地址</span>
57</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>3)启动</strong></p><p>然后配置启动项,注意重命名并且配置新的端口,避免冲突。</p><p><code>VM options: -Dserver.port=8083</code></p><p>访问nacos控制台,可以发现服务注册成功。</p><h3 id="_4、服务发现" tabindex="-1"><a class="header-anchor" href="#_4、服务发现"><span>4、服务发现</span></a></h3><p>服务的消费者要去nacos订阅服务,这个过程就是服务发现</p><div class="hint-container info"><p class="hint-container-title">步骤如下:</p><ul><li>引入依赖</li><li>配置Nacos地址</li><li>发现并调用服务</li></ul></div><p><strong>1)引入依赖</strong></p><p>服务发现除了要引入nacos依赖以外,由于还需要负载均衡,因此要引入SpringCloud提供的LoadBalancer依赖。</p><p>我们在<code>cart-service</code>中的<code>pom.xml</code>中添加下面的依赖:</p><div class="language-xml line-numbers-mode" data-ext="xml" data-title="xml"><pre class="language-xml"><code><span class="token comment">&lt;!--nacos 服务注册发现--&gt;</span>
58<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
59    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>com.alibaba.cloud<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
60    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-cloud-starter-alibaba-nacos-discovery<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
61<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
62</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>2)配置Nacos地址</strong></p><p>在<code>cart-service</code>的<code>application.yml</code>中添加nacos地址配置:</p><div class="language-yaml line-numbers-mode" data-ext="yml" data-title="yml"><pre class="language-yaml"><code><span class="token key atrule">spring</span><span class="token punctuation">:</span>
63  <span class="token key atrule">cloud</span><span class="token punctuation">:</span>
64    <span class="token key atrule">nacos</span><span class="token punctuation">:</span>
65      <span class="token key atrule">server-addr</span><span class="token punctuation">:</span> 192.168.150.101<span class="token punctuation">:</span><span class="token number">8848</span>
66</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>3)发现并调用服务</strong></p><p>接下来,服务调用者<code>cart-service</code>就可以去订阅<code>item-service</code>服务了。不过item-service有多个实例,而真正发起调用时只需要知道一个实例的地址。</p><p>因此,服务调用者必须利用负载均衡的算法,从多个实例中挑选一个去访问。常见的负载均衡算法有:</p><ul><li>随机</li><li>轮询</li><li>IP的hash</li><li>最近最少访问</li><li>...</li></ul><p>这里我们可以选择最简单的随机负载均衡。</p><p>另外,服务发现需要用到一个工具,<code>DiscoveryClient</code>,SpringCloud已经帮我们自动装配,我们可以直接注入使用:</p><div class="language-java line-numbers-mode" data-ext="java" data-title="java"><pre class="language-java"><code>
66        <span class="token comment">//2.1、根据服务名称获取服务列表</span>
67        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ServiceInstance</span><span class="token punctuation">&gt;</span></span> instances <span class="token operator">=</span> discoveryClient<span class="token punctuation">.</span><span class="token function">getInstances</span><span class="token punctuation">(</span><span class="token string">&quot;item-service&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
68        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token class-name">CollUtils</span><span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span>instances<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
69            <span class="token keyword">return</span><span class="token punctuation">;</span>
70        <span class="token punctuation">}</span>
71        <span class="token comment">//2.2、手写负载均衡,从实例列表中选择一个实例 </span>
72        <span class="token class-name">ServiceInstance</span> instance <span class="token operator">=</span> instances<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token class-name">RandomUtil</span><span class="token punctuation">.</span><span class="token function">randomInt</span><span class="token punctuation">(</span>instances<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//随机负载均衡</span>
73
74        <span class="token comment">//2.3.1、利用restTemplate 发起HTTP请求,得到HTTP响应</span>
75        <span class="token class-name">ResponseEntity</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">ItemDTO</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span> response <span class="token operator">=</span> restTemplate<span class="token punctuation">.</span><span class="token function">exchange</span><span class="token punctuation">(</span>
76                instance<span class="token punctuation">.</span><span class="token function">getUri</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;/items?ids={ids}&quot;</span><span class="token punctuation">,</span>
77                <span class="token class-name">HttpMethod</span><span class="token punctuation">.</span><span class="token constant">GET</span><span class="token punctuation">,</span>
78                <span class="token keyword">null</span><span class="token punctuation">,</span>
79                <span class="token keyword">new</span> <span class="token class-name">ParameterizedTypeReference</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">List</span><span class="token punctuation">&lt;</span><span class="token class-name">ItemDTO</span><span class="token punctuation">&gt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
80                <span class="token punctuation">}</span><span class="token punctuation">,</span>
81                <span class="token class-name">Map</span><span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span><span class="token string">&quot;ids&quot;</span><span class="token punctuation">,</span> <span class="token class-name">CollUtils</span><span class="token punctuation">.</span><span class="token function">join</span><span class="token punctuation">(</span>itemIds<span class="token punctuation">,</span> <span class="token string">&quot;,&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
82        <span class="token punctuation">)</span><span class="token punctuation">;</span>
83        <span class="token comment">//2.3.2、解析响应</span>
84        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span>response<span class="token punctuation">.</span><span class="token function">getStatusCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">is2xxSuccessful</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
85            <span class="token keyword">return</span><span class="token punctuation">;</span>
86        <span class="token punctuation">}</span>
87        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ItemDTO</span><span class="token punctuation">&gt;</span></span> items <span class="token operator">=</span> response<span class="token punctuation">.</span><span class="token function">getBody</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
88</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h2 id="三、远程调用-openfeign" tabindex="-1"><a class="header-anchor" href="#三、远程调用-openfeign"><span>三、远程调用(OpenFeign)</span></a></h2><p>​ 我们利用Nacos实现了服务的治理,利用RestTemplate实现了服务的远程调用。但是远程调用的代码太复杂了:而且这种调用方式,与原本的本地方法调用差异太大,编程时的体验也不统一,一会儿远程调用,一会儿本地调用。因此,我们必须想办法改变远程调用的开发模式,让<strong>远程调用像本地方法调用一样简单</strong>。而这就要用到<strong>OpenFeign</strong>组件了。</p><div class="hint-container tip"><p class="hint-container-title">其实远程调用的关键点就在于四个:</p><ul><li>请求方式</li><li>请求路径</li><li>请求参数</li><li>返回值类型</li></ul></div><p>所以,OpenFeign就利用SpringMVC的相关注解来声明上述4个参数,然后基于动态代理帮我们生成远程调用的代码,而无需我们手动再编写,非常方便。</p><h3 id="_1、快速入门" tabindex="-1"><a class="header-anchor" href="#_1、快速入门"><span>1、快速入门</span></a></h3><p><strong>1)引入依赖</strong></p><p>在<code>cart-service</code>服务的pom.xml中引入<code>OpenFeign</code>的依赖和<code>loadBalancer</code>依赖:</p><div class="language-xml line-numbers-mode" data-ext="xml" data-title="xml"><pre class="language-xml"><code>  <span class="token comment">&lt;!--openFeign--&gt;</span>
89  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
90      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.cloud<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
91      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-cloud-starter-openfeign<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
92  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
93  <span class="token comment">&lt;!--负载均衡器--&gt;</span>
94  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
95      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.cloud<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
96      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-cloud-starter-loadbalancer<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
97  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
98</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>2)启用OpenFeign</strong></p><p>接下来,我们在<code>cart-service</code>的<code>CartApplication</code>启动类上添加注解,启动OpenFeign功能:</p><div class="language-java line-numbers-mode" data-ext="java" data-title="java"><pre class="language-java"><code><span class="token annotation punctuation">@EnableFeignClients</span>
99<span class="token annotation punctuation">@MapperScan</span><span class="token punctuation">(</span><span class="token string">&quot;com.hmall.cart.mapper&quot;</span><span class="token punctuation">)</span>
100<span class="token annotation punctuation">@SpringBootApplication</span>
101<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CartApplication</span> <span class="token punctuation">{</span>
102    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
103        <span class="token class-name">SpringApplication</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">CartApplication</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
104    <span class="token punctuation">}</span>
105
106    <span class="token annotation punctuation">@Bean</span>
107    <span class="token keyword">public</span> <span class="token class-name">RestTemplate</span> <span class="token function">restTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
108        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">RestTemplate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
109    <span class="token punctuation">}</span>
110<span class="token punctuation">}</span>
111</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>3)编写OpenFeign客户端</strong></p><p>在<code>cart-service</code>中,定义一个新的接口,编写Feign客户端:</p><p>其中代码如下:</p><div class="language-java line-numbers-mode" data-ext="java" data-title="java"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>hmall<span class="token punctuation">.</span>cart<span class="token punctuation">.</span>client</span><span class="token punctuation">;</span>
112
113<span class="token keyword">
113import</span> <span class="token import"><span class="token namespace">com<span class="token punctuation">.</span>hmall<span class="token punctuation">.</span>cart<span class="token punctuation">.</span>domain<span class="token punctuation">.</span>dto<span class="token punctuation">.</span></span><span class="token class-name">ItemDTO</span></span><span class="token punctuation">;</span>
114<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>cloud<span class="token punctuation">.</span>openfeign<span class="token punctuation">.</span></span><span class="token class-name">FeignClient</span></span><span class="token punctuation">;</span>
115<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">GetMapping</span></span><span class="token punctuation">;</span>
116<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">RequestParam</span></span><span class="token punctuation">;</span>
117
118<span class="token keyword">import</span> <span class="token import"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">List</span></span><span class="token punctuation">;</span>
119
120<span class="token annotation punctuation">@FeignClient</span><span class="token punctuation">(</span><span class="token string">&quot;item-service&quot;</span><span class="token punctuation">)</span>
121<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">ItemClient</span> <span class="token punctuation">{</span>
122
123    <span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/items&quot;</span><span class="token punctuation">)</span>
124    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">ItemDTO</span><span class="token punctuation">&gt;</span></span> <span class="token function">queryItemByIds</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestParam</span><span class="token punctuation">(</span><span class="token string">&quot;ids&quot;</span><span class="token punctuation">)</span> <span class="token class-name">Collection</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Long</span><span class="token punctuation">&gt;</span></span> ids<span class="token punctuation">)</span><span class="token punctuation">;</span>
125<span class="token punctuation">}</span>
126</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>这里只需要声明接口,无需实现方法</p><div class="hint-container tip"><p class="hint-container-title">接口中的几个关键信息</p><ul><li><code>@FeignClient(&quot;item-service&quot;)</code> :声明服务名称</li><li><code>@GetMapping</code> :声明请求方式</li><li><code>@GetMapping(&quot;/items&quot;)</code> :声明请求路径</li><li><code>@RequestParam(&quot;ids&quot;) Collection&lt;Long&gt; ids</code> :声明请求参数</li><li><code>List&lt;ItemDTO&gt;</code> :返回值类型</li></ul></div><p><strong>4)使用FeignClient</strong></p><div class="language-java line-numbers-mode" data-ext="java" data-title="java"><pre class="language-java"><code><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">
126ItemDTO</span><span class="token punctuation">&gt;</span></span> items <span class="token operator">=</span> itemClient<span class="token punctuation">.</span><span class="token function">queryItemByIds</span><span class="token punctuation">(</span>itemIds<span class="token punctuation">)</span><span class="token punctuation">;</span>
127</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>feign替我们完成了服务拉取、负载均衡、发送http请求的所有工作。</p><h3 id="_2、连接池" tabindex="-1"><a class="header-anchor" href="#_2、连接池"><span>2、连接池</span></a></h3><p>Feign底层发起http请求,依赖于其它的框架。</p><div class="hint-container info"><p class="hint-container-title">其底层支持的http客户端实现包括</p><ul><li>HttpURLConnection:默认实现,不支持连接池</li><li>Apache HttpClient :支持连接池</li><li>OKHttp:支持连接池</li></ul></div><p>因此我们通常会使用带有连接池的客户端来代替默认的HttpURLConnection。比如,我们使用OK Http.</p><p><strong>1)引入依赖</strong></p><p>在<code>cart-service</code>的<code>pom.xml</code>中引入依赖:</p><div class="language-xml line-numbers-mode" data-ext="xml" data-title="xml"><pre class="language-xml"><code><span class="token comment">&lt;!--OK http 的依赖 --&gt;</span>
128<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
129  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>io.github.openfeign<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
130  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>feign-okhttp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
131<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
132</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>2)开启连接池</strong></p><p>在<code>cart-service</code>的<code>application.yml</code>配置文件中开启Feign的连接池功能:</p><div class="language-yaml line-numbers-mode" data-ext="yml" data-title="yml"><pre class="language-yaml"><code><span class="token key atrule">feign</span><span class="token punctuation">:</span>
133  <span class="token key atrule">okhttp</span><span class="token punctuation">:</span>
134    <span class="token key atrule">enabled</span><span class="token punctuation">:</span> <span class="token boolean important">true</span> <span class="token comment"># 开启OKHttp功能</span>
135</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>重启服务,连接池就生效了。</p><h3 id="_3、结构优化" tabindex="-1"><a class="header-anchor" href="#_3、结构优化"><span>3、结构优化</span></a></h3><p>如果拆分了交易微服务(<code>trade-service</code>),它也需要远程调用<code>item-service</code>中的根据id批量查询商品功能。这个需求与<code>cart-service</code>中是一样的。因此,我们就需要在<code>trade-service</code>中再次定义<code>ItemClient</code>接口,这不是重复编码吗? 有什么办法能加避免重复编码呢?</p><h4 id="_1-思路分析" tabindex="-1"><a class="header-anchor" href="#_1-思路分析"><span>1)思路分析</span></a></h4><p>避免重复编码的办法就是<strong>抽取</strong>。不过这里有两种抽取思路:</p><ul><li>思路1:抽取到微服务之外的公共module</li><li>思路2:每个微服务自己抽取一个module</li></ul><figure><img src="`+k+'" alt="" tabindex="0" loading="lazy"><figcaption></figcaption></figure><p>方案1抽取更加简单,工程结构也比较清晰,但缺点是整个项目耦合度偏高。</p><p>方案2抽取相对麻烦,工程结构相对更复杂,但服务之间耦合度降低。</p><h4 id="_2-抽取feign客户端" tabindex="-1"><a class="header-anchor" href="#_2-抽取feign客户端"><span>2)抽取Feign客户端</span></a></h4><p>在<code>hmall</code>下定义一个新的module,命名为hm-api,然后把ItemDTO和ItemClient都拷贝过来,最终结构如下:</p><figure><img src="'+m+`" alt="" tabindex="0" loading="lazy"><figcaption></figcaption></figure><p>现在,任何微服务要调用<code>item-service</code>中的接口,只需要引入<code>hm-api</code>模块依赖即可,无需自己编写Feign客户端了。</p><p>接下来,我们在<code>cart-service</code>的<code>pom.xml</code>中引入<code>hm-api</code>模块:</p><div class="language-xml line-numbers-mode" data-ext="xml" data-title="xml"><pre class="language-xml"><code>  <span class="token comment">&lt;!--feign模块--&gt;</span>
136  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
137      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>com.heima<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
138      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>hm-api<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
139      <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>version</span><span class="token punctuation">&gt;</span></span>1.0.0<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>version</span><span class="token punctuation">&gt;</span></span>
140  <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
141</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="hint-container warning"><p class="hint-container-title">启动类上添加声明</p><p>在cart-service的启动类上添加声明</p><p><code>@EnableFeignClients(basePackages = &quot;com.hmall.api.client&quot;)</code></p><p>或者声明要用的FeignClient</p><p><code>@EnableFeignClients(clients= {ItemClient.class})</code></p><p>否则会扫描不到<code>ItemClient</code>,从而报错</p></div><h3 id="_4、日志配置" tabindex="-1"><a class="header-anchor" href="#_4、日志配置"><span>4、日志配置</span></a></h3><p>OpenFeign只会在FeignClient所在包的日志级别为<strong>DEBUG</strong>时,才会输出日志。而且其日志级别有4级:</p><ul><li><strong>NONE</strong>:不记录任何日志信息,这是默认值。</li><li><strong>BASIC</strong>:仅记录请求的方法,URL以及响应状态码和执行时间</li><li><strong>HEADERS</strong>:在BASIC的基础上,额外记录了请求和响应的头信息</li><li><strong>FULL</strong>:记录所有请求和响应的明细,包括头信息、请求体、元数据。</li></ul><p>Feign默认的日志级别就是NONE,所以默认我们看不到请求日志。</p><p><strong>1)定义日志级别</strong></p><p>在hm-api模块下新建一个配置类,定义Feign的日志级别:</p><div class="language-java line-numbers-mode" data-ext="java" data-title="java"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>hmall<span class="token punctuation">.</span>api<span class="token punctuation">.</span>config</span><span class="token punctuation">;</span>
142
143<span class="token keyword">import</span> <span class="token import"><span class="token namespace">feign<span class="token punctuation">.</span></span><span class="token class-name">Logger</span></span><span class="token punctuation">;</span>
144<span class="token keyword">import</span> <span class="token import"><span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Bean</span></span><span class="token punctuation">;</span>
145
146<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">DefaultFeignConfig</span> <span class="token punctuation">{</span>
147    <span class="token annotation punctuation">@Bean</span>
148    <span class="token keyword">public</span> <span class="token class-name">Logger<span class="token punctuation">.</span>Level</span> <span class="token function">feignLogLevel</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
149        <span class="token keyword">return</span> <span class="token class-name">Logger<span class="token punctuation">.</span>Level</span><span class="token punctuation">.</span><span class="token constant">FULL</span><span class="token punctuation">;</span>
150    <span class="token punctuation">}</span>
151<span class="token punctuation">}</span>
152</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><strong>2)配置</strong></p><p>接下来,要让日志级别生效,还需要配置这个类。有两种方式:</p><ul><li><strong>局部</strong>生效:在某个<code>FeignClient</code>中配置,只对当前<code>FeignClient</code>生效</li></ul><div class="language-Java line-numbers-mode" data-ext="Java" data-title="Java"><pre class="language-Java"><code>@FeignClient(value = &quot;item-service&quot;, configuration = DefaultFeignConfig.class)
153</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><ul><li><strong>全局</strong>生效:在<code>@EnableFeignClients</code>中配置,针对所有<code>FeignClient</code>生效。</li></ul><div class="language-Java line-numbers-mode" data-ext="Java" data-title="Java"><pre class="language-Java"><code>@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)
154</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><h3 id="_5、openfeign-传递用户" tabindex="-1"><a class="header-anchor" href="#_5、openfeign-传递用户"><span>5、OPenFeign 传递用户</span></a></h3>`,134);function b(h,f){const n=a("RouteLink");return i(),t("div",null,[e("more-"),v,p("p",null,[c(n,{to:"/posts/old%E5%AD%98%E6%A1%A3/springcloud/%E7%BB%9F%E4%B8%80%E7%BD%91%E5%85%B3%E8%B7%AF%E7%94%B1_4.html"},{default:o(()=>[u("参考网关部分")]),_:1})])])}const x=s(g,[["render",b],["__file","服务注册与远程调用.html.vue"]]),C=JSON.parse('{"path":"/posts/old%E5%AD%98%E6%A1%A3/springcloud/%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%8E%E8%BF%9C%E7%A8%8B%E8%B0%83%E7%94%A8.html","title":"服务注册与远程调用","lang":"zh-CN","frontmatter":{"title":"服务注册与远程调用","date":"2024-06-21T00:00:00.000Z","tags":"SpringCloud","category":"SpringCloud","order":3,"icon":"/img/nacos.svg","description":"服务注册与远程调用 一、介绍 在拆分黑马商城的时候,我们发现一个问题:就是购物车业务中需要查询商品信息,但商品信息查询的逻辑全部迁移到了item-service服务,导致我们无法查询。 最终结果就是查询到的购物车数据不完整,因此要想解决这个问题,我们就必须改造其中的代码,把原本本地方法调用,改造成跨微服务的远程调用(RPC,即Remote Produc...","head":[["meta",{"property":"og:url","content":"https://mister-hope.github.io/posts/old%E5%AD%98%E6%A1%A3/springcloud/%E6%9C%8D%E5%8A%A1%E6%B3%A8%E5%86%8C%E4%B8%8E%E8%BF%9C%E7%A8%8B%E8%B0%83%E7%94%A8.html"}],["meta",{"property":"og:site_name","content":"Lance"}],["meta",{"property":"og:title","content":"服务注册与远程调用"}],["meta",{"property":"og:description","content":"服务注册与远程调用 一、介绍 在拆分黑马商城的时候,我们发现一个问题:就是购物车业务中需要查询商品信息,但商品信息查询的逻辑全部迁移到了item-service服务,导致我们无法查询。 最终结果就是查询到的购物车数据不完整,因此要想解决这个问题,我们就必须改造其中的代码,把原本本地方法调用,改造成跨微服务的远程调用(RPC,即Remote Produc..."}],["meta",{"property":"og:type","content":"article"}],["meta",{"property":"og:image","content":"https://mister-hope.github.io/image/cloud/cloud1.jpg"}],["meta",{"property":"og:locale","content":"zh-CN"}
154],["meta",{"property":"og:updated_time","content":"2026-02-10T11:21:07.000Z"}],["meta",{"property":"article:author","content":"RuyiWei"}],["meta",{"property":"article:published_time","content":"2024-06-21T00:00:00.000Z"}],["meta",{"property":"article:modified_time","content":"2026-02-10T11:21:07.000Z"}],["script",{"type":"application/ld+json"},"{\\"@context\\":\\"https://schema.org\\",\\"@type\\":\\"Article\\",\\"headline\\":\\"服务注册与远程调用\\",\\"image\\":[\\"https://mister-hope.github.io/image/cloud/cloud1.jpg\\",\\"https://mister-hope.github.io/image/cloud/cloud1.png\\",\\"https://mister-hope.github.io/image/cloud/cloud2.jpg\\",\\"https://mister-hope.github.io/image/cloud/cloud2.png\\"],\\"datePublished\\":\\"2024-06-21T00:00:00.000Z\\",\\"dateModified\\":\\"2026-02-10T11:21:07.000Z\\",\\"author\\":[{\\"@type\\":\\"Person\\",\\"name\\":\\"RuyiWei\\"}]}"]]},"headers":[{"level":2,"title":"一、介绍","slug":"一、介绍","link":"#一、介绍","children":[{"level":3,"title":"1、RestTemplate","slug":"_1、resttemplate","link":"#_1、resttemplate","children":[]},{"level":3,"title":"2、远程调用","slug":"_2、远程调用","link":"#_2、远程调用","children":[]},{"level":3,"title":"3、缺点","slug":"_3、缺点","link":"#_3、缺点","children":[]}]},{"level":2,"title":"二、服务注册(Nacos)","slug":"二、服务注册-nacos","link":"#二、服务注册-nacos","children":[{"level":3,"title":"1、注册中心原理","slug":"_1、注册中心原理","link":"#_1、注册中心原理","children":[]},{"level":3,"title":"2、Nacos注册中心","slug":"_2、nacos注册中心","link":"#_2、nacos注册中心","children":[]},{"level":3,"title":"3、服务注册","slug":"_3、服务注册","link":"#_3、服务注册","children":[]},{"level":3,"title":"4、服务发现","slug":"_4、服务发现","link":"#_4、服务发现","children":[]}]},{"level":2,"title":"三、远程调用(OpenFeign)","slug":"三、远程调用-openfeign","link":"#三、远程调用-openfeign","children":[{"level":3,"title":"1、快速入门","slug":"_1、快速入门","link":"#_1、快速入门","children":[]},{"level":3,"title":"2、连接池","slug":"_2、连接池","link":"#_2、连接池","children":[]},{"level":3,"title":"3、结构优化","slug":"_3、结构优化","link":"#_3、结构优化","children":[]},{"level":3,"title":"4、日志配置","slug":"_4、日志配置","link":"#_4、日志配置","children":[]},{"level":3,"title":"5、OPenFeign 传递用户","slug":"_5、openfeign-传递用户","link":"#_5、openfeign-传递用户","children":[]}]}],"git":{"createdTime":1719643575000,"updatedTime":1770722467000,"contributors":[{"name":"weiruyi","email":"[email protected]","commits":1}]},"readingTime":{"minutes":11.33,"words":3399},"filePathRelative":"posts/old存档/springcloud/服务注册与远程调用.md","localizedDate":"2024å¹´6月21日","excerpt":"<!--more--->\\n<h1>服务注册与远程调用</h1>\\n<h2>一、介绍</h2>\\n<p>在拆分黑马商城的时候,我们发现一个问题:就是购物车业务中需要查询商品信息,但商品信息查询的逻辑全部迁移到了<code>item-service</code>服务,导致我们无法查询。</p>\\n<p>最终结果就是查询到的购物车数据不完整,因此要想解决这个问题,我们就必须改造其中的代码,把原本本地方法调用,改造成跨微服务的远程调用(RPC,即<strong>R</strong>emote <strong>P</strong>roduce <strong>C</strong>all)。</p>\\n<p>那么问题来了:我们该如何跨服务调用,准确的说,如何在<code>cart-service</code>中获取<code>item-service</code>服务中的提供的商品数据呢?</p>","autoDesc":true}');export{x as comp,C as data};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.