java架構之路-(微服務專題)feign的基本使用和nacos的配置中心
上次迴歸:
上次我們說了ribbon的基本使用,包括裡面的內部演算法,演算法的細粒度配置,還有我們自己如何實現我們自己的演算法,主要還是一些基本使用的知識,還不會使用ribbon的小夥伴可以回去看一下上一篇部落格。
什麼是Feign:
Feign是Netflix開發的宣告式、模板化的HTTP客戶端,其靈感來自Retrofit、JAXRS2.0以及WebSocket。Feign 可幫助我們更加便捷、優雅地呼叫HTTP API,為什麼我們會選擇使用Feign呢?我們上次說到的ribbon也是可以呼叫遠端API的啊,但是你的請求地址引數很多呢?比如這樣https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E5%B0%8F%E8%8F%9C%E6%8A%80%E6%9C%AF&rsv_pq=c848f94a0022633c&rsv_t=82132w5e6o2pWnrOzzEl1kRwfItDYCuNU7FotoIqlCHTCjD2WiDKjarInW8&rqlang=cn&rsv_enter=1&rsv_dl=tb&rsv_sug3=13&rsv_sug1=1&rsv_sug7=100&rsv_sug2=0&inputT=1408&rsv_sug4=1408,而且引數還總是變化的(客戶每天都在變需求),你每次都需要改寫程式碼,地址太長還容易寫錯,是不是覺得寫起來很吃力的樣子,我們這次學習的Feign就是來解決這個問題的。
Feign的常用配置詳解:
剛才我們簡單的說到了Feign是做什麼的,我們來看一下,我們如何使用Feign吧。還是我們的兩個服務,一個使用者服務,一個訂單服務,我們分別來看一下配置。
一、最簡單的啟動
①.首先加入父依賴包,在啟動類加入註解@EnableFeignClients
<!-- 加入Feign依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
package com.xiaocaiFeign; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableFeignClients @EnableDiscoveryClient public class FeignOrderApplication { public static void main(String[] args) { SpringApplication.run(FeignOrderApplication.class, args); } }
②.建立我們的訂單服務,建立一個介面,介面如下,需要加註解@FeignClient(name = "feign-order"),實現類你們自己去完成吧
package com.xiaocaiFeign.controller; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @FeignClient(name = "feign-order") public interface OrderController { @RequestMapping("/getOrderData/{orderId}") String getOrderData(@PathVariable("orderId") String orderId); }
③.修改我們的訂單服務的POM檔案,弄成一個jar包即可,不需要可執行的jar包。
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-jar-plugin</artifactId> </plugin> </plugins> </build>
④.建立我們的使用者服務,將我們的訂單服務以jar包的形式引入進來。
<dependencies> <dependency> <groupId>com</groupId> <artifactId>feignOrder</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies>
這裡千萬注意一個問題,你的訂單服務和你的使用者服務,包路徑一定要相同,不然springboot是掃描不到你的包的,切記~!!!
⑤.編寫我們的呼叫類(使用者服務)
package com.xiaocaiFeign.controller; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class UserController { @Autowired private OrderController orderController; @GetMapping("/getOrder") public String getOrderData() { System.out.println("準備呼叫"); String orderData = orderController.getOrderData("1"); System.out.println(orderData); return orderData; } }
執行看結果
是不是超級簡單。
二、列印日誌級別
首先我們在訂單服務加入一個配置,千萬別寫@Configuration
package com.xiaocaiFeign.config; import feign.Logger; import org.springframework.context.annotation.Bean; public class FeignLogConfig { @Bean public Logger.Level level() { //return Logger.Level.NONE; //(預設)不列印任何日誌 return Logger.Level.BASIC;//僅記錄請求方法、URL、響應狀態程式碼以及執行時間,生成一般用這個 //return Logger.Level.HEADERS;//在BASIC基礎之上還記錄了請求和響應的header. //return Logger.Level.FULL;//記錄了請求和響應的header、body和元資料 } }
然後在我們的介面類下面給予這個配置
package com.xiaocaiFeign.controller; import com.xiaocaiFeign.config.FeignLogConfig; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @FeignClient(name = "feign-order", configuration = FeignLogConfig.class) public interface OrderController { @RequestMapping("/getOrderData/{orderId}") String getOrderData(@PathVariable("orderId") String orderId); }
最後我們在我們的使用者服務中開啟配置,注意xiaocaiFeign是你的包名。
logging: level: com: xiaocaiFeign: debug
我們來看一下效果,我這隻演示一下FULL的吧~!
三、額外我覺得沒用的配置,契約配置
反正我是覺得沒啥大用,而且還不熟悉的,和我們的日誌差不多,加入一個自定義的配置類
package com.xiaocaiFeign.config; import feign.Contract; import org.springframework.context.annotation.Bean; public class MyFeignConfig { /** * 根據SpringBoot自動裝配FeignClientsConfiguration 的FeignClient的契約是SpringMvc * 通過修改契約為預設的Feign的鍥約,那麼就可以使用預設的註解 * @return */ @Bean public Contract feiContract() { return new Contract.Default(); } }
然後通過介面引入,但是這回介面必須要寫feign的註解了,我覺得沒這個必要,我還是比較習慣用springMVC的註解。
package com.xiaocaiFeign.controller; import com.xiaocaiFeign.config.MyFeignConfig; import feign.Param; import feign.RequestLine; import org.springframework.cloud.openfeign.FeignClient; @FeignClient(name = "feign-order", configuration = MyFeignConfig.class) public interface OrderController { @RequestLine("GET /getOrderData/{orderId}") String getOrderData(@Param("orderId") String orderId); }
這寫就可以呼叫了,裡面都別寫錯了,寫錯了,使用者服務可能會啟動失敗的。
四、請求頭傳遞
最後一個例項了,假如我們這樣的,使用者服務呼叫訂單服務,訂單服務每次呼叫需要攜帶請求頭token進行驗證,我們又該如何來做呢?我們來看一下程式碼實現,先弄一個攔截器。
package com.xiaocaiFeign.config; import feign.RequestInterceptor; import feign.RequestTemplate; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; public class MyRequestInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate template) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); template.header("token", request.getHeader("token")); } }
然後將攔截器配置到Feign下面去。
package com.xiaocaiFeign.controller; import com.xiaocaiFeign.config.FeignLogConfig; import com.xiaocaiFeign.config.MyFeignConfig; import com.xiaocaiFeign.config.MyRequestInterceptor; import feign.Param; import feign.RequestLine; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @FeignClient(name = "feign-order",configuration = MyRequestInterceptor.class) public interface OrderController { @RequestMapping("/getOrderData/{orderId}") String getOrderData(@PathVariable("orderId") String orderId); // @RequestLine("GET /getOrderData/{orderId}") // String getOrderData(@Param("orderId") String orderId); @RequestMapping("/getOrderToken") String getOrderToken(); }
自己去測試一下呼叫結果吧,我弄這個弄了好久,保證沒問題的,我就不上圖了。
Feign的優化配置:
我們的Feign底層還是使用Ribbon來呼叫的,第一次很多時候會呼叫的慢,我可以改為HTTPClient呼叫方式。
feign: client: config: connectTimeout: 5000 #連線超時時間(毫秒) readTimeout: 5000 # 讀取超時時間(毫秒) product-center: loggerLevel: full # 日誌級別 contract: feign.Contract.Default #指定預設契約 httpclient: enabled: true # 開啟httpClient max-connections: 200 # 最大連線數 max-connections-per-route: 50 # 為每個url請求設定最大連線數
nacos配置中心詳解:
nacos裡面還有一個配置中心還沒有去說,我們現在的專案很多都是微服務的,也知道微服務會拆分成很多個小的服務,加入你拆分的不多,10個服務,本地開發環境,公共開發環境,測試環境,生產環境,那麼你就意味著你需要弄40個配置檔案,而且你會暴露你的資料庫地址給開發,那麼我們這次就用nacos來看看配置中心是如何做的吧。我們先弄一個最簡單的測試類。
package com.nacosConfig.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class ConfigCenterController { @Value("${config.center.name}") private String name; @GetMapping("/") public String getData() { System.out.println(name); return name; } }
server: port: 8080 config: center: name: "張三"
先不用nacos配置中心,我們來測試一下。
我們來看一下nacos是怎麼來配置的
①.加入依賴包。
<!-- 引入nacos配置依賴--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-nacos-config</artifactId> </dependency>
②.新建一個叫做bootstrap.yml的配置,這個配置會優先於springboot自帶的application.yml配置。
spring: application: name: nacos profiles: active: config cloud: nacos: config: server-addr: 192.168.138.119:8848 namespace: 83cbe7a9-7713-4d5c-b052-a42ba1df9e84 file-extension: yml
來解釋一下我們的配置,第一個spring.application.name=nacos是我們的檔名字,spring.profiles.active=config還是我們的檔名字,spring.cloud.nacos.config.file-extension=yml是檔案字尾,就是說,我們會去拿名字為nacos-config.yml這個檔案。連線和命令空間這裡就不說了,在nacos的註冊中心講的已經很詳細了。
③.登入nacos頁面,點選配置列表,選擇對應的名稱空間,點選“+”進行新增。
就這樣,一個簡單的配置中心就完成了(啟動會報錯,是因為你的註冊中心沒有註冊成功報錯的)。而且還可以檢視歷史版本,用起來還是不錯的,你可以在application.yml寫入你的註冊配置,如下所示
spring: application: name: nacos-config cloud: nacos: discovery: server-addr: 192.168.138.119:8848
這時專案啟動的時候會自動拉取nacos-config.yml配置檔案。這樣寫是什麼意思呢?就是你一個shoppingServer,你有不同的環境,我們寫一個通用的配置shoppingServer.yml,然後通過你的shoppingServer-dev.yml、shoppingServer-st.yml,等檔案來細化咱們的不同環境的配置。
還有一個配置是這樣的。
spring: application: name: nacos-config profiles: active: dev cloud: nacos: config: server-addr: 192.168.138.119:8848 file-extension: yml shared-dataids: config1.yml,config2.yml
就是說我們還有載入config1.yml和config2.yml配置檔案。現在我們說到四個配置檔案了,那麼他們的順序又是什麼呢?config1.yml<<<config2.yml<<<nacos-config.yml<<<nacos-config-dev.yml,越是在後面載入的,權利越大,就是後面的配置可以覆蓋掉前面的配置。這裡的shared-dataids: config1.yml,config2.yml一般用於不同系統中的通用配置,比如我們在使用者系統和訂單系統有通用配置,我們可以通過shared-dataids的方式來引入配置。
還可以這樣來寫
spring: application: name: nacos-config profiles: active: dev cloud: nacos: config: server-addr: 192.168.138.119:8848 file-extension: yml shared-dataids: config1.yml,config2.yml refreshable-dataids: config1.yml,config2.yml ext-config: - data-id: config3.yml group: DEFAULT_GROUP refresh: true - data-id: config4.yml group: DEFAULT_GROUP refresh: true
這回又多了一些檔案,順序是什麼樣子的呢?我再來寫一下config1.yml<<<config2.yml<<<config3.yml<<<config4.yml<<<nacos-config.yml<<<nacos-config-dev.yml。
spring: application: name: nacos-config profiles: active: dev cloud: refresh: enabled: true # 預設是true nacos: config: server-addr: 192.168.138.119:8848 file-extension: yml shared-dataids: config1.yml,config2.yml refreshable-dataids: config1.yml,config2.yml ext-config: - data-id: config3.yml group: DEFAULT_GROUP refresh: true - data-id: config4.yml group: DEFAULT_GROUP refresh: false
其中標紅的那個幾個值是控制是否可以動態重新整理的,就是說我們改了配置中心的配置,不用重啟服務,配置就可以生效的,需要在類上面加入@RefreshScope註解。
最後一個問題,nacos改密碼和新增賬戶,我們叢集的時候連線一個mysql資料庫對吧,單機的比較頭疼,我們設定單機的內部是用一個Derby這個資料庫來連線的,我這裡只能用IDEA改本地的Derby然後拷貝到linux上去,暫時沒啥別的好辦法,用頁面也能改,但是無法新增使用者,而我們的叢集是用的mysql,我們可以自己操作啦,來一個新增使用者的操作,開啟我們的mysql的nacos庫,找到users表,新增使用者,然後我們用下面的方法來手動生成密碼。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> <version>1.2.2.RELEASE</version> </dependency>
public static void main(String[] args) { String nacos = new BCryptPasswordEncoder().encode("nacos"); System.out.println("nacos = " + nacos); }
然後把我們的密碼自己弄到mysql資料庫內就可以啦
總結:
這次主要說了feign的基本使用,日誌級別的選擇,還有我們的請求頭如何傳遞,然後就是我們的Nacos的配置中心是如何去做的,我們配置檔案的載入順序,最後是我們的nacos如何新增使用者和修改密碼(頁面就可以改)。
最進弄了一個公眾號,小菜技術,歡迎大家的加入
&n