上次回歸:
上次我們說了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如何添加用戶和修改密碼(頁面就可以改)。
最進弄了一個公眾號,小菜技術,歡迎大家的加入