day02
使用OpenFeign依賴
openfeign用于遠程服務調用,通常與負載均衡插件loadbalancer一起使用
連接池
Feign底層發起http請求,依賴于其它的框架。其底層支持的http客戶端實現包括:
- HttpURLConnection:默認實現,不支持連接池
- Apache HttpClient :支持連接池
- OKHttp:支持連接池
通常使用帶連接池的客戶端來替代默認的客戶端
以OKHttp為例:
- 引入pom依賴
<!--OK http 的依賴 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
- 在yaml文件配置開啟連接池,默認關閉
feign:
okhttp:
enabled: true # 開啟OKHttp功能
- 重啟服務,連接池生效
配置openfeign的日志輸出
OpenFeign只會在FeignClient所在包的日志級別為DEBUG時,才會輸出日志。而且其日志級別有4級:
- NONE:不記錄任何日志信息,這是默認值。
- BASIC:僅記錄請求的方法,URL以及響應狀態碼和執行時間
- HEADERS:在BASIC的基礎上,額外記錄了請求和響應的頭信息
- FULL:記錄所有請求和響應的明細,包括頭信息、請求體、元數據。
Feign默認的日志級別就是NONE,所以默認我們看不到請求日志。
- 定義日志級別
新建一個配置類,添加
@Bean方法,返回值為openfeign日志級別的枚舉變量package com.hmall.api.config; import feign.Logger; import org.springframework.context.annotation.Bean; public class DefaultFeignConfig { @Bean public Logger.Level feignLogLevel(){ return Logger.Level.BASIC; } }
- 配置日志生效
有兩種方式:
- 局部生效:在某個
FeignClient中配置,只對當前FeignClient生效@FeignClient(value = "item-service", configuration = DefaultFeignConfig.class)
- 全局生效:在
@EnableFeignClients中配置,針對所有FeignClient生效。@EnableFeignClients(basePackages = "com.hmall.api.client", defaultConfiguration = DefaultFeignConfig.class)
網關
利用網關,可以用于用戶請求的轉發和負載均衡,比如用戶所有請求均通過
8080發出,經過網關路由轉發到對應的微服務的對應節點創建一個網關分為以下步驟:
- 創建網關微服務
- 引入SpringCloudGateway、NacosDiscovery依賴
- 編寫啟動類
- 配置網關路由
創建網關
-
創建網關微服務模塊
-
引入SpringCloudGateway、NacosDiscovery依賴
<dependencies>
<!--網關-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!--nacos discovery-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--負載均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
- 創建啟動類
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class);
}
}
- 編寫路由配置
server:
port: 8080
spring:
application:
name: gateway-server
cloud:
nacos:
server-addr: 192.168.48.100:8848
gateway:
routes:
- id: item-service # 路由名稱:item-service
uri: lb://item-service # 負載均衡轉發到指定服務
predicates: # 路由斷言,配置路由-服務命中的條件
- Path=/items/**,/search/** # 這里通過請求路徑前綴判斷
filters: # 局部路由過濾器,可設置多個過濾器
- filter1=xxx
- id: item-service # 路由名稱:user-service
uri: lb://user-service
predicates:
- Path=/users/**,/addresses/**
default-filters: # 全局路由過濾器,與routes同級
自定義過濾器
- 網關請求處理流程
網關過濾器鏈中的過濾器有兩種:
GatewayFilter:路由過濾器,作用范圍比較靈活,可以是任意指定的路由Route.GlobalFilter:全局過濾器,作用范圍是所有路由,不可配置。
- 自定義GlobalFilter
自定義GlobalFilter需要實現GlobalFilter, Ordered(用于指定過濾器優先級)接口
@Component
public class PrintAnyGlobalFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 編寫過濾器邏輯
}
@Override
public int getOrder() {
// 過濾器執行順序,值越小,優先級越高
return 0;
}
}
- 傳遞信息:網關->微服務
網關傳遞信息給微服務很簡單:
- 在網關過濾器中將信息添加到請求頭
//在網關過濾器中修改請求頭的方法 ServerWebExchange newEx = exchange.mutate() .request(b -> b.header("user-info", user_info)) .build(); return chain.filter(newEx);
- 接著在SpringMVC的攔截器中獲取信息并存入ThreadLocal中
這里有一個可能會碰到的錯誤,如果把該攔截器配置到
spring.foctories文件中實現自動裝配,那么如果網關引入了該攔截器所在的模塊,那么會導致網關缺失MVC依賴錯誤,因為攔截器是SpringMVC層的,解決方法就是使用條件裝配@ConditionalOnClass(DispatcherServlet.class),只在擁有SpringMVC的環境中裝配該Bean
- 傳遞信息:微服務->微服務
微服務之間調用是基于OpenFeign來實現的,發起的也是http請求,因此也可以通過
請求頭攜帶的方式來傳遞信息,openfeign提供了一個攔截器接口feign.RequestInterceptor,只需要實現該接口并實現apply方法,然后利用RequestTemplate對象來修改請求頭。這樣一來,每次OpenFeign發起請求的時候都會調用該方法,傳遞用戶信息。
- 實現RequestInterceptor以及apply方法
@Bean public RequestInterceptor userInfoRequestInterceptor(){ return new RequestInterceptor() { @Override public void apply(RequestTemplate requestTemplate) { Long id = UserContext.getUser(); if (id != null){ requestTemplate.header("user-info",id.toString()); //添加請求頭 } } }; }
微服務消息傳遞流程:
配置管理
配置共享
將多個微服務中共同的配置信息抽取到nacos配置文件,由nacos統一管理
實現步驟:
- 添加相關依賴
<!--nacos配置管理--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--讀取bootstrap文件--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>
- 抽取微服務中共同的配置信息到nacos中
![]()
- 添加
bootstrap.yaml文件由于讀取Nacos配置是SpringCloud上下文(
ApplicationContext)初始化時處理的,發生在項目的引導階段。然后才會初始化SpringBoot上下文,去讀取application.yaml,所以目前無法讀取到nacos地址,也就不能拉去配置信息。但springcloud上下文在初始化時會讀取一個bootstrap.yaml文件,可以在其中配置nacos的信息
- 添加
bootstrap.yaml文件- 編寫配置信息
spring: application: name: cart-service profiles: active: dev cloud: nacos: server-addr: 192.168.48.100:8848 config: file-extension: yaml shared-configs: - dataId: shared-jdbc.yaml - dataId: shared-log.yaml - dataId: shared-swagger.yaml
- 修改
application.yaml配置內容,添加相關配置鍵值對,刪除重復配置
配置熱啟動
nacos支持配置熱啟動,可無需重啟便能修改配置信息
- 在nacos中添加配置文件(命名格式有限制),編寫配置信息
dataId: [微服務名]-[spring.active.profile].[后綴名] //配置文件內容 hm: cart: maxAmount: 1 # 購物車商品數量上限
- 在微服務中使用
@ConfigurationProperties注解讀取配置信息
Nacos動態路由
Nacos可以配置動態路由,將路由信息保存在nacos配置管理中,動態的
添加/刪除路由信息,不用重啟路由服務使用的依賴:
<!--統一配置管理--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--加載bootstrap--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency>通過注入
RouteDefinitionWriter(用于更新內存中的路由配置信息)和NacosConfigManager(用于拉取nacos路由配置信息和監聽配置信息變化)的bean對象
- 拉取并監聽nacos路由配置信息
String configInfo = nacosConfigManager.getConfigService() .getConfigAndSignListener(dataId, group, 5000, new Listener() { @Override public Executor getExecutor() { return null; } @Override public void receiveConfigInfo(String configInfo) { updateConfigInfo(configInfo); } });
- 更新內存路由配置
writer.delete(Mono.just(routeId)).subscribe(); //routeId為String類型 writer.save(Mono.just(routeDefinition)).subscribe();

浙公網安備 33010602011771號