SpringCloud微服務開發與實戰

本節內容帶你認識什么是微服務的特點,微服務的拆分,會使用Nacos實現服務治理,會使用OpenFeign實現遠程調用(通過黑馬商城來帶你了解實際開發中微服務項目)

前言:從谷歌搜索指數來看,國內從自2016年底開始,微服務熱度突然暴漲

那么:到底什么是微服務?


目錄

主要內容

1.認識微服務

1.1.單體架構

1.2.微服務

1.3.SpringCloud

2.微服務拆分

2.1.熟悉黑馬商城

2.1.1.登錄

2.2.2.搜索商品

2.2.3.購物車

2.2.4.下單

2.2.5.支付

2.2.服務拆分原則

2.2.1.什么時候拆

2.2.2.怎么拆

2.3.拆分購物車、商品服務

2.3.1.商品服務

2.4.服務調用

2.4.1.RestTemplate

2.4.2.遠程調用

3.服務注冊和發現

3.1.注冊中心原理

3.2.Nacos注冊中心

3.3.服務注冊

3.3.1.添加依賴

3.3.2.配置Nacos

3.3.3.啟動服務實例

3.4.服務發現

3.4.1.引入依賴

3.4.2.配置Nacos地址

3.4.3.發現并調用服務

4.OpenFeign

4.1.快速入門

4.1.1.引入依賴

4.1.2.啟用OpenFeign

4.1.3.編寫OpenFeign客戶端

4.1.4.使用FeignClient

4.2.連接池

4.2.1.引入依賴

4.2.2.開啟連接池

4.3.最佳實踐

4.3.1.思路分析

4.3.2.抽取Feign客戶端

4.3.3.掃描包

4.4.日志配置

4.4.1.定義日志級別

4.4.2.配置


主要內容

  • 知道單體架構的特點

  • 知道微服務架構的特點

  • 學會拆分微服務

  • 會使用Nacos實現服務治理

  • 會使用OpenFeign實現遠程調用


1.認識微服務

1.1.單體架構

單體架構(monolithic structure):顧名思義,整個項目中所有功能模塊都在一個工程中開發;項目部署時需要對所有模塊一起編譯、打包;項目的架構設計、開發模式都非常簡單。

當項目規模較小時,這種模式上手快,部署、運維也都很方便,因此早期小項目都采用這種模式。

但隨著項目的業務規模越來越大,團隊開發人員也不斷增加,單體架構就呈現出越來越多的問題

  • 團隊協作成本高:團隊數十個人同時協作開發同一個項目,由于所有模塊都在一個項目中,不同模塊的代碼之間物理邊界越來越模糊。

  • 系統發布效率低:任何模塊變更都需要發布整個系統,而系統發布過程中需要多個模塊之間制約較多,需要對比各種文件,任何一處出現問題都會導致發布失敗,往往一次發布需要數十分鐘甚至數小時。

  • 系統可用性差:單體架構各個功能模塊是作為一個服務部署,相互之間會互相影響,一些熱點功能會耗盡系統資源,導致其它服務低可用。


1.2.微服務

微服務架構,首先是服務化,就是將單體架構中的功能模塊從單體應用中拆分出來,獨立部署為多個服務。同時要滿足下面的一些特點

  • 單一職責:一個微服務負責一部分業務功能,并且其核心數據不依賴于其它模塊。

  • 團隊自治:每個微服務都有自己獨立的開發、測試、發布、運維人員,團隊人員規模不超10人

  • 服務自治:每個微服務都獨立打包部署,訪問自己獨立的數據庫。并且要做好服務隔離,避免對其它服務產生影響

那么,單體架構存在的問題有沒有解決呢?

  • 團隊協作成本高?

    • 由于服務拆分,每個服務代碼量大大減少,參與開發的后臺人員較少,協作成本大大降低

  • 系統發布效率低?

    • 每個服務都是獨立部署,當有某個服務有代碼變更時,只需要打包部署該服務即可

  • 系統可用性差?

    • 每個服務獨立部署,并且做好服務隔離,使用自己的服務器資源,不會影響到其它服務

當然,微服務架構在拆分的過程中,還會面臨很多其它問題:

  • 如果出現跨服務的業務該如何處理?

  • 頁面請求到底該訪問哪個服務?

  • 如何實現各個服務之間的服務隔離?

這些問題,我們在下面會給大家逐一解答。


1.3.SpringCloud

微服務拆分以后碰到的各種問題都有對應的解決方案和微服務組件,而SpringCloud框架可以說是目前Java領域最全面的微服務組件的集合了。

而且SpringCloud依托于SpringBoot的自動裝配能力,大大降低了其項目搭建、組件使用的成本。對于沒有自研微服務組件能力的中小型企業,使用SpringCloud全家桶來實現微服務開發可以說是最合適的選擇!

SpringCloud官網https://b11et3un53m.feishu.cn/wiki/R4Sdwvo8Si4kilkSKfscgQX0niB#N8judeJvGors0yxVEU7cCudwnjp


2.微服務拆分

接下來,我們就一起將黑馬商城這個單體項目拆分為微服務項目,并解決其中出現的各種問題。

2.1.熟悉黑馬商城

首先,我們需要熟悉黑馬商城項目的基本結構:

2.1.1.登錄

首先來看一下登錄業務流程:

2.2.2.搜索商品

在首頁搜索框輸入關鍵字,點擊搜索即可進入搜索列表頁面:

2.2.3.購物車

在搜索到的商品列表中,點擊按鈕加入購物車,即可將商品加入購物車:

2.2.4.下單

在購物車頁面點擊結算按鈕,會進入訂單結算頁面:

點擊提交訂單,會提交請求到服務端,服務端做3件事情:

  • 創建一個新的訂單

  • 扣減商品庫存

  • 清理購物車中商品

2.2.5.支付

下單完成后會跳轉到支付頁面,目前只支持余額支付

在選擇余額支付這種方式后,會發起請求到服務端,服務端會立刻創建一個支付流水單,并返回支付流水單號到前端。

當用戶輸入用戶密碼,然后點擊確認支付時,頁面會發送請求到服務端,而服務端會做幾件事情:

  • 校驗用戶密碼

  • 扣減余額

  • 修改支付流水狀態

  • 修改交易訂單狀態


2.2.服務拆分原則

服務拆分一定要考慮幾個問題:

  • 什么時候拆?

  • 如何拆?

2.2.1.什么時候拆

對于多數小型項目,一般是先采用單體架構,隨著用戶規模擴大、業務復雜后再逐漸拆分為微服務架構。問題就是后期服務拆分時,可能會遇到代碼耦合帶來的問題,拆分較為困難(前易后難

對于一些大型項目,在立項之初目的就很明確,為了長遠考慮,在架構設計時就直接選擇微服務架構。雖然前期投入較多,但后期就少了拆分服務的煩惱前難后易

2.2.2.怎么拆

之前我們說過,微服務拆分時粒度要小,這其實是拆分的目標。

高內聚首先是單一職責,同時保證微服務內部業務的完整性為前提,一旦微服務做到了高內聚,那么服務之間的耦合度自然就降低了。

當然,微服務之間不可避免的會有或多或少的業務交互,比如下單時需要查詢商品數據。這個時候我們不能在訂單服務直接查詢商品數據庫,否則就導致了數據耦合。而應該由商品服務對應暴露接口,并且一定要保證微服務對外接口的穩定性(盡量保證接口外觀不變)。雖然出現了服務間調用,但此時無論你如何在商品服務做內部修改,都不會影響到訂單微服務,服務間的耦合度就降低了。


明確了拆分目標,接下來就是拆分方式了。我們在做服務拆分時一般有兩種方式:

  • 縱向拆分

  • 橫向拆分

所謂縱向拆分,就是按照項目的功能模塊來拆分。例如黑馬商城中,就有用戶管理功能、訂單管理功能、購物車功能、商品管理功能、支付功能等。那么按照功能模塊將他們拆分為一個個服務,就屬于縱向拆分。這種拆分模式可以盡可能提高服務的內聚性。

橫向拆分,是看各個功能模塊之間有沒有公共的業務部分,如果有將其抽取出來作為通用服務。例如用戶登錄是需要發送消息通知,記錄風控數據,下單時也要發送短信,記錄風控數據。因此消息發送、風控數據記錄就是通用的業務功能,因此可以將他們分別抽取為公共服務:消息中心服務、風控管理服務。這樣可以提高業務的復用性,避免重復開發。同時通用業務一般接口穩定性較強,也不會使服務之間過分耦合。


2.3.拆分購物車、商品服務

一般微服務項目有兩種不同的工程結構:

  • 完全解耦:每一個微服務都創建為一個獨立的工程,項目完全解耦。

    • 優點:服務之間耦合度低

    • 缺點:每個項目都有自己的獨立倉庫,管理麻煩

  • Maven聚合:整個項目為一個Project,然后每個微服務是其中的一個Module

    • 優點:項目代碼集中,管理和運維方便

    • 缺點:服務之間耦合,編譯時間較長

2.3.1.商品服務

引入依賴:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>hmall</artifactId><groupId>com.heima</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>item-service</artifactId><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target></properties><dependencies><!--common--><dependency><groupId>com.heima</groupId><artifactId>hm-common</artifactId><version>1.0.0</version></dependency><!--web--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--數據庫--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!--mybatis--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId></dependency><!--單元測試--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies><build><finalName>${project.artifactId}</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

代碼如下:

package com.hmall.item;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.hmall.item.mapper")
@SpringBootApplication
public class ItemApplication {public static void main(String[] args) {SpringApplication.run(ItemApplication.class, args);}
}

需要改變的地方

這也是因為ItemMapper的所在包發生了變化,因此這里代碼必須修改包路徑。

最后,還要導入數據庫表。默認的數據庫連接的是虛擬機,在你docker數據庫執行課前資料提供的SQL文件:(idea自帶的數據庫)

開啟啟動類:

接著,啟動項目,訪問商品微服務的swagger接口文檔:http://localhost:8081/doc.html

然后測試其中的根據id批量查詢商品這個接口:

2.4.服務調用

在拆分的時候,我們發現一個問題:就是購物車業務中需要查詢商品信息,但商品信息查詢的邏輯全部遷移到item-service服務,導致我們無法查詢。

最終結果就是查詢到的購物車數據不完整,因此要想解決這個問題,我們就必須改造其中的代碼,把原本本地方法調用,改造成跨微服務的遠程調用(RPC,即Remote Produce Call)。

因此,現在查詢購物車列表的流程變成了這樣:

那么:我們該如何用Java代碼發送Http的請求呢?

2.4.1.RestTemplate

Spring給我們提供了一個RestTemplate的API,可以方便的實現Http請求的發送。

同步客戶端執行HTTP請求,在底層HTTP客戶端庫(如JDK HttpURLConnection、Apache HttpComponents等)上公開一個簡單的模板方法API。RestTemplate通過HTTP方法為常見場景提供了模板,此外還提供了支持不太常見情況的通用交換和執行方法。 RestTemplate通常用作共享組件。然而,它的配置不支持并發修改,因此它的配置通常是在啟動時準備的。如果需要,您可以在啟動時創建多個不同配置的RestTemplate實例。如果這些實例需要共享HTTP客戶端資源,它們可以使用相同的底層ClientHttpRequestFactory。 注意:從5.0開始,這個類處于維護模式,只有對更改和錯誤的小請求才會被接受。請考慮使用webclient,它有更現代的API,支持同步、異步和流場景。

先將RestTemplate注冊為一個Bean:

package com.hmall.cart.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;@Configuration
public class RemoteCallConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

重點:

此處不用@Resource和@Autowired,是為了避免循環依賴

故而可以采用構造方法的方式來使用bean對象

但是,這樣代碼非常繁瑣,故而可以使用@AllArgsConstructor來自動生成構造函數

然而,這樣還會出現一個問題,并不是每一個成員變量都需要生成對應的構造方法

因此,可以在需要的成員變量上面添加final關鍵字,同時加上@RequiredArgsConstructor,使其變為常量

2.4.2.遠程調用

完整代碼如下:

private void handleCartItems(List<CartVO> vos) {// TODO 1.獲取商品idSet<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());// 2.查詢商品// List<ItemDTO> items = itemService.queryItemByIds(itemIds);// 2.1.利用RestTemplate發起http請求,得到http的響應ResponseEntity<List<ItemDTO>> response = restTemplate.exchange("http://localhost:8081/items?ids={ids}",HttpMethod.GET,null,new ParameterizedTypeReference<List<ItemDTO>>() {},Map.of("ids", CollUtil.join(itemIds, ",")));// 2.2.解析響應if(!response.getStatusCode().is2xxSuccessful()){// 查詢失敗,直接結束return;}List<ItemDTO> items = response.getBody();if (CollUtils.isEmpty(items)) {return;}// 3.轉為 id 到 item的mapMap<Long, ItemDTO> itemMap = items.stream().collect(Collectors.toMap(ItemDTO::getId, Function.identity()));// 4.寫入vofor (CartVO v : vos) {ItemDTO item = itemMap.get(v.getItemId());if (item == null) {continue;}v.setNewPrice(item.getPrice());v.setStatus(item.getStatus());v.setStock(item.getStock());}
}

3.服務注冊和發現

3.1.注冊中心原理

在微服務遠程調用的過程中,包括兩個角色:

  • 服務提供者:提供接口供其它微服務訪問

  • 服務消費者:調用其它微服務提供的接口

在大型微服務項目中,服務提供者的數量會非常多,為了管理這些服務就引入了注冊中心的概念。注冊中心、服務提供者、服務消費者三者間關系如下:

3.2.Nacos注冊中心

目前開源的注冊中心框架有很多,國內比較常見的有:

  • Eureka:Netflix公司出品,目前被集成在SpringCloud當中,一般用于Java應用

  • Nacos:Alibaba公司出品,目前被集成在SpringCloudAlibaba中,一般用于Java應用

  • Consul:HashiCorp公司出品,目前集成在SpringCloud中,不限制微服務語言

以上幾種注冊中心都遵循SpringCloud中的API規范,因此在業務開發使用上沒有太大差異。由于Nacos是國內產品,中文文檔比較豐富,而且同時具備配置管理功能(后面會學習),因此在國內使用較多,課堂中我們會Nacos為例來學習。

官方網站如下:

我們基于Docker來部署Nacos的注冊中心,首先我們要準備MySQL數據庫表,用來存儲Nacos的數據。由于是Docker部署,所以大家需要將資料中的SQL文件導入到你Docker中的MySQL容器中:

然后,將課前資料中的nacos目錄上傳至虛擬機的/root目錄。

進入root目錄,然后執行下面的docker命令:

docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
nacos/nacos-server:v2.1.0-slim

執行下面代碼

 docker logs -f nacos

啟動完成后,訪問下面地址:http://192.168.150.101:8848/nacos/,注意將192.168.150.101替換為你自己的虛擬機IP地址。

首次訪問會跳轉到登錄頁,賬號密碼都是nacos

3.3.服務注冊

接下來,我們把item-service注冊到Nacos,步驟如下:

  • 引入依賴

  • 配置Nacos地址

  • 重啟

3.3.1.添加依賴

item-servicepom.xml中添加依賴:

<!--nacos 服務注冊發現-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

3.3.2.配置Nacos

item-serviceapplication.yml中添加nacos地址配置:

spring:application:name: item-service # 服務名稱cloud:nacos:server-addr: 192.168.150.101:8848 # nacos地址

3.3.3.啟動服務實例

3.4.服務發現

服務的消費者要去nacos訂閱服務,這個過程就是服務發現,步驟如下:

  • 引入依賴

  • 配置Nacos地址

  • 發現并調用服務

3.4.1.引入依賴

服務發現除了要引入nacos依賴以外,由于還需要負載均衡,因此要引入SpringCloud提供的LoadBalancer依賴。

我們在cart-service中的pom.xml中添加下面的依賴:

<!--nacos 服務注冊發現-->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

可以發現,這里Nacos的依賴于服務注冊時一致,這個依賴中同時包含了服務注冊和發現的功能。因為任何一個微服務都可以調用別人,也可以被別人調用,即可以是調用者,也可以是提供者。

因此,等一會兒cart-service啟動,同樣會注冊到Nacos

3.4.2.配置Nacos地址

cart-serviceapplication.yml中添加nacos地址配置:

spring:cloud:nacos:server-addr: 192.168.150.101:8848

3.4.3.發現并調用服務

接下來,服務調用者cart-service就可以去訂閱item-service服務了。不過item-service有多個實例,而真正發起調用時只需要知道一個實例的地址。

因此,服務調用者必須利用負載均衡的算法,從多個實例中挑選一個去訪問。常見的負載均衡算法有:

  • 隨機

  • 輪詢

  • IP的hash

  • 最近最少訪問

這里我們可以選擇最簡單的隨機負載均衡。

另外,服務發現需要用到一個工具,DiscoveryClient,SpringCloud已經幫我們自動裝配,我們可以直接注入使用:

我們就可以對原來的遠程調用做修改了,之前調用時我們需要寫死服務提供者的IP和端口:

但現在不需要了,我們通過DiscoveryClient發現服務實例列表,然后通過負載均衡算法,選擇一個實例去調用:

4.OpenFeign

在上一章,我們利用Nacos實現了服務的治理,利用RestTemplate實現了服務的遠程調用。但是遠程調用的代碼太復雜了:

而且這種調用方式,與原本的本地方法調用差異太大,編程時的體驗也不統一,一會兒遠程調用,一會兒本地調用。

因此,我們必須想辦法改變遠程調用的開發模式,讓遠程調用像本地方法調用一樣簡單。而這就要用到OpenFeign組件了。

其實遠程調用的關鍵點就在于四個:

  • 請求方式

  • 請求路徑

  • 請求參數

  • 返回值類型

所以,OpenFeign就利用SpringMVC的相關注解來聲明上述4個參數,然后基于動態代理幫我們生成遠程調用的代碼,而無需我們手動再編寫,非常方便。

接下來,我們就通過一個快速入門的案例來體驗一下OpenFeign的便捷吧。

4.1.快速入門

我們還是以cart-service中的查詢我的購物車為例。因此下面的操作都是在cart-service中進行。

4.1.1.引入依賴

cart-service服務的pom.xml中引入OpenFeign的依賴和loadBalancer依賴:

  <!--openFeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--負載均衡器--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency>

4.1.2.啟用OpenFeign

接下來,我們在cart-serviceCartApplication啟動類上添加注解,啟動OpenFeign功能:

4.1.3.編寫OpenFeign客戶端

cart-service中,定義一個新的接口,編寫Feign客戶端:

其中代碼如下:

package com.hmall.cart.client;@FeignClient("item-service")
public interface ItemClient {@GetMapping("/items")List<ItemDTO> queryItemByIds(@RequestParam("ids") Collection<Long> ids);
}

這里只需要聲明接口,無需實現方法。接口中的幾個關鍵信息:

  • @FeignClient("item-service"):聲明服務名稱

  • @GetMapping:聲明請求方式

  • @GetMapping("/items"):聲明請求路徑

  • @RequestParam("ids") Collection<Long> ids:聲明請求參數

  • List<ItemDTO>:返回值類型

有了上述信息,OpenFeign就可以利用動態代理幫我們實現這個方法,并且發送一個GET請求,攜帶ids為請求參數,并自動將返回值處理為List<ItemDTO>

我們只需要直接調用這個方法,即可實現遠程調用了。

4.1.4.使用FeignClient

最后,我們在cart-servicecom.hmall.cart.service.impl.CartServiceImpl中改造代碼,直接調用ItemClient的方法:

修改前

修改之后

feign替我們完成了服務拉取、負載均衡、發送http請求的所有工作,是不是看起來優雅多了。

而且,這里我們不再需要RestTemplate了,還省去了RestTemplate的注冊。

4.2.連接池

Feign底層發起http請求,依賴于其它的框架。其底層支持的http客戶端實現包括:

  • HttpURLConnection:默認實現,不支持連接池

  • Apache HttpClient :支持連接池

  • OKHttp:支持連接池

因此我們通常會使用帶有連接池的客戶端來代替默認的HttpURLConnection。比如,我們使用OK Http.

4.2.1.引入依賴

cart-servicepom.xml中引入依賴:

<!--OK http 的依賴 -->
<dependency><groupId>io.github.openfeign</groupId><artifactId>feign-okhttp</artifactId>
</dependency>

4.2.2.開啟連接池

cart-serviceapplication.yml配置文件中開啟Feign的連接池功能:

feign:okhttp:enabled: true # 開啟OKHttp功能

重啟服務,連接池就生效了。

4.3.最佳實踐

4.3.1.思路分析

相信大家都能想到,避免重復編碼的辦法就是抽取。不過這里有兩種抽取思路:

  • 思路1:抽取到微服務之外的公共module

  • 思路2:每個微服務自己抽取一個module

思路1

優點:項目耦合度大幅度降低

缺點:項目結構變得更加復雜

思路2

方案1抽取相對麻煩,工程結構相對更復雜,但服務之間耦合度降低。

方案2抽取更加簡單,工程結構也比較清晰,但缺點是整個項目耦合度偏高。

4.3.2.抽取Feign客戶端

由于item-service已經創建好,無法繼續拆分,因此這里我們采用方案2

hmall下定義一個新的module,命名為hm-api

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.heima</groupId><artifactId>hmall</artifactId><version>1.0.0</version></parent><artifactId>hm-api</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--openFeign--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!--負載均衡器--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-loadbalancer</artifactId></dependency><dependency><groupId>io.swagger</groupId><artifactId>swagger-annotations</artifactId><version>1.6.6</version><scope>compile</scope></dependency></dependencies>
</project>

4.3.3.掃描包

接下來,我們在cart-servicepom.xml中引入hm-api模塊:

  <!--feign模塊--><dependency><groupId>com.heima</groupId><artifactId>hm-api</artifactId><version>1.0.0</version></dependency>

這里因為ItemClient現在定義到了com.hall.api.client包下,而cart-service的啟動類定義在com.hall.cart包下,掃描不到ItemClient,所以報錯了。

4.4.日志配置

OpenFeign只會在FeignClient所在包的日志級別為DEBUG時,才會輸出日志。而且其日志級別有4級:

  • NONE:不記錄任何日志信息,這是默認值。

  • BASIC:僅記錄請求的方法,URL以及響應狀態碼和執行時間

  • HEADERS:在BASIC的基礎上,額外記錄了請求和響應的頭信息

  • FULL:記錄所有請求和響應的明細,包括頭信息、請求體、元數據。

Feign默認的日志級別就是NONE,所以默認我們看不到請求日志。

4.4.1.定義日志級別

在hm-api模塊下新建一個配置類,定義Feign的日志級別:

package com.hmall.api.config;import feign.Logger;
import org.springframework.context.annotation.Bean;public class DefaultFeignConfig {@Beanpublic Logger.Level feignLogLevel(){return Logger.Level.FULL;}
}

4.4.2.配置

接下來,要讓日志級別生效,還需要配置這個類。有兩種方式:

  • 局部生效:在某個FeignClient中配置,只對當前FeignClient生效

@FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)
  • 全局生效:在@EnableFeignClients中配置,針對所有FeignClient生效。

@EnableFeignClients(defaultConfiguration = DefaultFeignConfig.class)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/81267.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/81267.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/81267.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

pgsql14自動創建表分區

最近有pgsql的分區表功能需求&#xff0c;沒想到都2025年了&#xff0c;pgsql和mysql還是沒有自身支持自動創建分區表的功能 現在pgsql數據庫層面還是只能用老三樣的辦法來處理這個問題&#xff0c;每個方法各有優劣 1. 觸發器 這是最傳統的方法&#xff0c;通過創建一個觸發…

math toolkit for real-time development讀書筆記一三角函數快速計算(1)

一、基礎知識 根據高中知識我們知道&#xff0c;很多函數都可以用泰勒級數展開。正余弦泰勒級數展開如下&#xff1a; 將其進一步抽象為公式可知&#xff1a; 正弦和余弦的泰勒級數具有高度結構化的模式&#xff0c;可拆解為以下核心特征&#xff1a; 1. 符號交替特性 正弦級…

uni-app 中適配 App 平臺

文章目錄 前言? 1. App 使用的 Runtime 架構&#xff1a;**WebView 原生容器&#xff08;plus runtime&#xff09;**&#x1f4cc; 技術棧核心&#xff1a; ? 2. WebView Native 的通信機制詳解&#xff08;JSBridge&#xff09;&#x1f4e4; Web → Native 調用&#xf…

SpringBoot基礎(靜態資源導入)

靜態資源導入 在WebMvcAutoConfiguration自動配置類中 有一個添加資源的方法&#xff1a; public void addResourceHandlers(ResourceHandlerRegistry registry) { //如果靜態資源已經被自定義了&#xff0c;則直接生效if (!this.resourceProperties.isAddMappings()) {logg…

基于OpenCV的人臉識別:LBPH算法

文章目錄 引言一、概述二、代碼實現1. 代碼整體結構2. 導入庫解析3. 訓練數據準備4. 標簽系統5. 待識別圖像加載6. LBPH識別器創建7. 模型訓練8. 預測執行9. 結果輸出 三、 LBPH算法原理解析四、關鍵點解析五、改進方向總結 引言 人臉識別是計算機視覺領域的一個重要應用&…

ElasticSearch重啟之后shard未分配問題的解決

以下是Elasticsearch重啟后分片未分配問題的完整解決方案&#xff0c;結合典型故障場景與最新實踐&#xff1a; 一、快速診斷定位 ?檢查集群狀態 GET /_cluster/health?pretty # status為red/yellow時需關注unassigned_shards字段值 ? 2.查看未分配分片詳情 …

CSS- 3.1 盒子模型-塊級元素、行內元素、行內塊級元素和display屬性

本系列可作為前端學習系列的筆記&#xff0c;代碼的運行環境是在HBuilder中&#xff0c;小編會將代碼復制下來&#xff0c;大家復制下來就可以練習了&#xff0c;方便大家學習。 HTML系列文章 已經收錄在前端專欄&#xff0c;有需要的寶寶們可以點擊前端專欄查看&#xff01; 點…

Git/GitLab日常使用的命令指南來了!

在 GitLab 中拉取并合并代碼的常見流程是通過 Git 命令來完成的。以下是一個標準的 Git 工作流&#xff0c;適用于從遠程倉庫&#xff08;如 GitLab&#xff09;拉取代碼、切換分支、合并更新等操作。 &#x1f310; 一、基礎命令&#xff1a;拉取最新代碼 # 拉取遠程倉庫的所…

HTML 表格與div深度解析區別及常見誤區

一、HTML<div>元素詳解 <div>是HTML中最基本的塊級容器元素&#xff0c;本身沒有語義&#xff0c;主要用于組織和布局頁面內容。以下是其核心用法&#xff1a; 1. 基礎結構與特性 <div><!-內部可包含任意HTML元素 --><h2>標題</h2><p…

mybatisPlus 新增時 其他字段的值和 id 保持一致實現方法

MyBatis-Plus 實現 sp_id_path 與 id 同步的方案 要實現新增時 sp_id_path 自動與 id 保持一致&#xff0c;需要在實體類和插入邏輯中做相應處理。MyBatis-Plus 提供了幾種方式來實現這一需求&#xff1a; 方案一&#xff1a;使用 MyBatis-Plus 的自動填充功能 這是最優雅的…

蘭亭妙微設計:為生命科技賦予人性化的交互語言

在醫療科技日新月異的今天&#xff0c;卓越的硬件性能唯有匹配恰如其分的交互語言&#xff0c;方能真正發揮價值。作為專注于醫療UI/UX設計的專業團隊&#xff0c;蘭亭妙微設計&#xff08;www.lanlanwork.com&#xff09;始終相信&#xff1a;每一處像素的排布&#xff0c;都應…

Tcping詳細使用教程

Tcping詳細使用教程 下載地址 https://download.elifulkerson.com/files/tcping/0.39/在windows環境下安裝tcping 在以上的下載地中找到exe可執行文件&#xff0c;其中tcping.exe適用于32位Windows系統&#xff0c;tcping64.exe適用于64位Windows操作系統。 其實tcping是個…

springCloud/Alibaba常用中間件之Seata分布式事務

文章目錄 SpringCloud Alibaba:依賴版本補充Seata處理分布式事務(AT模式)AT模式介紹核心組件介紹AT的工作流程&#xff1a;兩階段提交&#xff08;**2PC**&#xff09; Seata-AT模式使用Seata(2.0.0)下載、配置和啟動Seata案例實戰前置代碼添加全局注解 GlobalTransactional Sp…

COMSOL隨機參數化表面流體流動模擬

基于粗糙度表面的裂隙流研究對于理解地下水的流動、污染物傳輸以及與之相關的地質災害&#xff08;如滑坡&#xff09;等方面具有重要意義。本研究通過蒙特卡洛方法生成隨機表面形貌&#xff0c;并利用COMSOL Multiphysics對隨機參數化表面的微尺度流體流動進行模擬。 參數化…

初識——QT

QT安裝方法 一、項目創建流程 創建項目 入口&#xff1a;通過Qt Creator的歡迎頁面或菜單欄&#xff08;文件→新建項目&#xff09;創建新項目。 項目類型&#xff1a;選擇「Qt Widgets Application」。 路徑要求&#xff1a;項目路徑需為純英文且不含特殊字符。 構建系統…

7-15 計算圓周率

π?131?352!?3573!??357?(2n1)n!?? 輸入格式&#xff1a; 輸入在一行中給出小于1的閾值。 輸出格式&#xff1a; 在一行中輸出滿足閾值條件的近似圓周率&#xff0c;輸出到小數點后6位。 輸入樣例&#xff1a; 0.01輸出樣例&#xff1a; 3.132157 我的代碼 #i…

【圖片識別工具】批量單據識別批量重命名,批量OCR識別圖片文字并重命名,批量改名工具的使用步驟和注意事項

一、適用場景 ??財務與發票管理??&#xff1a;企業需處理大量電子發票或掃描件&#xff0c;通過OCR識別發票代碼、金額等關鍵信息&#xff0c;自動重命名為發票號_金額.pdf格式&#xff0c;便于歸檔與稅務審計。 ??物流單據處理??&#xff1a;物流公司需從運單中提取單…

Modbus TCP轉Profinet網關:數字化工廠異構網絡融合的核心樞紐

在現代工業生產中&#xff0c;隨著智能制造和工業互聯網的不斷發展&#xff0c;數字化工廠成為了制造業升級的重要方向。數字化工廠的核心在于實現設備、數據和人的互聯互通&#xff0c;而這其中&#xff0c;通信協議扮演著至關重要的角色。今天&#xff0c;我們就來探討開疆智…

win11平臺下的docker-desktop中的volume位置問題

因為需要搞個本地的mysql數據庫&#xff0c;而且本地安裝的程序較多&#xff0c;不想再安mysql了&#xff0c;就想到使用docker來安裝。而且因為數據巨大&#xff0c;所以想到直接使用轉移data文件夾的方式。 各種查詢&#xff0c;而且還使用ai查詢&#xff0c;他們都提到&…

【MySQL】項目實踐

個人主頁&#xff1a;Guiat 歸屬專欄&#xff1a;MySQL 文章目錄 1. 項目實踐概述1.1 項目實踐的重要性1.2 項目中MySQL的典型應用場景 2. 數據庫設計流程2.1 需求分析與規劃2.2 設計過程示例2.3 數據庫設計工具 3. 電子商務平臺實踐案例3.1 系統架構3.2 數據庫Schema設計3.3 數…