1.Feign是什麼?
在Spring Cloud Netflix棧中,每個微服務都以HTTP接口的形式暴露自身服務,因此在調用遠程服務時就必須使用到HTTP客戶端。我們可以使用JDK原生的URLConnection、Apache的Http Client、Netty的異步HTTP Client,還有之前我們使用到Spring的RestTemplate,這些都可以實現遠程調用。
Feign在RestTemplate的基礎上對其封裝,由它來幫助我們定義和實現依賴服務接口的定義。Spring Cloud Feign 基於Netflix Feign 實現的,整理Spring Cloud Ribbon 與 Spring Cloud Hystrix,並且實現了聲明式的Web服務客戶端定義方式。
2.Feign的基本使用
首先需要引入依賴
pom.xml
org.springframework.cloud spring-cloud-starter-openfeign 1.4.3.RELEASE
application.yml
server: port: 8900spring: application: name: consumer-order-feignuser: url: http://localhost:7900/user/eureka: client: service-url: defaultZone: http://user:user@localhost:8888/eureka/然後我們來看下其他項目中提供服務這塊提供的接口,和之前一樣
UserController.java
package com.ithzk.spring.cloud.controller;import com.ithzk.spring.cloud.entity.User;import com.netflix.discovery.EurekaClient;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RestController;/** * @author hzk * @date 2018/5/13 */@RestController("/")public class UserController { @Autowired private EurekaClient eurekaClient; @Value("${server.port}") private String port; @GetMapping("/user/{id}") public User getUser(@PathVariable Integer id){ return new User(id,"zs",20); } @GetMapping("/eureka/info") public String info(){ //InstanceInfo instanceInfo = eurekaClient.getNextServerFromEureka("PROVIDER-USER", false); //return instanceInfo.getHomePageUrl()+ ":" +instanceInfo.getPort(); return port; } @PostMapping("/get_user") public User getUser(User user){ user.setName("provider_user_get_user"); return user; }}根據提供者接口編寫Feign客戶端
CustomFeignClient.java
package com.ithzk.spring.cloud.feign;import com.ithzk.spring.cloud.entity.User;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.PostMapping;/** * @author hzk * @date 2018/5/20 */@FeignClient("PROVIDER-USER")public interface CustomFeignClient { //C版本的 spring 是不能寫 GETMAPPING 的必須用RequestMapping @GetMapping("/user/{id}") User getOrder(@PathVariable("id") Integer id); /** * 如果傳遞複雜參數,feign默認都會以方式去請求 * 無法訪問,提供者必須為post方式消費者才可使用,如果非要使用get傳遞多個數據,只能以普通方式傳遞 * @param user * @return */ @PostMapping("/get_user") User getUser(User user);}
OrderController.java
package com.ithzk.spring.cloud.controller;import com.ithzk.spring.cloud.entity.User;import com.ithzk.spring.cloud.feign.CustomFeignClient;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RestController;/** * @author hzk * @date 2018/5/13 */@RestControllerpublic class OrderController { @Autowired private CustomFeignClient customFeignClient; @GetMapping("/order/{id}") public User getOrder(@PathVariable Integer id){ User user = customFeignClient.getOrder(id); return user; } @GetMapping("/get_user") public User getUser(User user){ User feignUser = customFeignClient.getUser(user); return feignUser; }}加上@EnableFeignClients就可以使用feign客戶端,啟動後成功請求獲取數據,這就是feign的基本使用了
OrderApp.java
package com.ithzk.spring.cloud;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.EnableEurekaClient;import org.springframework.cloud.netflix.feign.EnableFeignClients;import org.springframework.context.annotation.Bean;import org.springframework.web.client.RestTemplate;/** * Hello world! * */@SpringBootApplication@EnableFeignClientspublic class OrderApp { //相當於xml中的bean標籤 用於調用當前方法獲取到指定的對象 @Bean public RestTemplate getRestTemplate(){ return new RestTemplate(); } public static void main( String[] args ) { SpringApplication.run(OrderApp.class); }}
3.Feign自定義配置
Feign客戶端本身有自己默認的配置,之前學習Ribbon的時候,未指定配置時會選擇Ribbon自身默認的配置,這裡也一樣,Feign也可以自定義配置。編寫配置類,這裡和Ribbon一樣,要確保不能被主類掃描到,否則未知錯誤,最簡單的方法依然是不放在和主類同包或子包下
MyFeignClientConfig.java
package com.ithzk.spring.config;import feign.Contract;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @author hzk * @date 2018/5/20 */@Configurationpublic class MyFeignClientConfig { /** * 將契約改為feign原生的默認契約。這樣就可以使用feign自帶的註解 * @return */ @Bean public Contract feignContract() { return new feign.Contract.Default(); }}自定義客戶端時指定使用配置類
CustomFeignClient.java
package com.ithzk.spring.cloud.feign;import com.ithzk.spring.cloud.entity.User;import com.ithzk.spring.config.MyFeignClientConfig;import feign.Param;import feign.RequestLine;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.PostMapping;/** * @author hzk * @date 2018/5/20 */@FeignClient(name = "PROVIDER-USER",configuration = MyFeignClientConfig.class)public interface CustomFeignClient { /** * 組合註解,第一個是請求方式,第二個是參數 用空格分割 * 注意使用RequestLine的時候必須使用 Param 註解 * 這裡的RequestLine是feign自帶註解,修改為feign默認契約後可以使用 * @param id * @return */ @RequestLine("GET /user/{id}") User getOrder(@Param("id") Integer id); /** * 如果傳遞複雜參數,feign默認都會以方式去請求 * 無法訪問,提供者必須為post方式消費者才可使用,如果非要使用get傳遞多個數據,只能以普通方式傳遞 * @param user * @return */ @RequestLine("GET /get_user") User getUser(User user);}這裡通過配置自定義配置,從而達成可以使用一些Feign提供的註解
4.Feign客戶端URL指定方式
上面我們通過name指定服務Feign客戶端,還有一種方式可以通過指定URL去注入Feign客戶端首先我們來看一下,Eureka服務的一些信息http://localhost:8888/eureka/apps http://localhost:8888/eureka/apps/CONSUMER-ORDER-FEIGN
可以看出來這裡麵包含了註冊在Eureka server上的服務的一些相關信息我們利用Feign客戶端去訪問試試
CustomFeignClientTwo.java
package com.ithzk.spring.cloud.feign;import com.ithzk.spring.config.MyFeignClientConfigTwo;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;/** * @author hzk * @date 2018/5/20 */@FeignClient(name = "customfeign",url = "http://localhost:8888/",configuration = MyFeignClientConfigTwo.class)public interface CustomFeignClientTwo { @RequestMapping("/eureka/apps/{servicename}") String getServicesName(@PathVariable("servicename") String servicename);}
MyFeignClientConfigTwo .java
package com.ithzk.spring.config;import feign.Contract;import feign.Logger;import feign.auth.BasicAuthRequestInterceptor;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @author hzk * @date 2018/5/20 */@Configurationpublic class MyFeignClientConfigTwo { /** * 用於創建用戶名和密碼的對象 * @return */ @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){ return new BasicAuthRequestInterceptor("user","user"); }}如果CustomFeignClientTwo 不加上這個自定義配置,並且裡面未配有用戶名密碼信息,則會出現權限問題無法獲取數據
啟動成功訪問http://localhost:8900/service/info/CONSUMER-ORDER-FEIGN
5.輸出日誌配置
Feign本身也提供了日誌輸出功能,只需配置文件加一些參數,對應自定義配置中設置級別即可
application.yml
server: port: 8900spring: application: name: consumer-order-feignuser: url: http://localhost:7900/user/eureka: client: service-url: defaultZone: http://user:user@localhost:8888/eureka/logging: level: com.ithzk.spring.cloud.feign.CustomFeignClientTwo: debug #給指定的 feign 設置日誌輸出級別,只有在 debug 的情況下才會打印日誌
MyFeignClientConfigTwo .java
package com.ithzk.spring.config;import feign.Logger;import feign.auth.BasicAuthRequestInterceptor;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @author hzk * @date 2018/5/20 */@Configurationpublic class MyFeignClientConfigTwo { /** * 用於創建用戶名和密碼的對象 * @return */ @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){ return new BasicAuthRequestInterceptor("user","user"); } /** * 配置要輸出的日誌是哪些,必須在debug 模式下才可以輸出 * */ @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; }}
這樣很簡單就配置好了日誌輸出
閱讀更多 丶灣裡小白龍 的文章