微服務實戰SpringCloud之Spring Cloud Feign


簡介

在項目中我們有時候需要調用第三方的API,微服務架構中這種情況則更是無法避免——各個微服務之間通信。比如一般的項目中,有時候我們會使用 HTTP Client 發送 HTTP 請求來進行調用,而在微服務架構,Spring Cloud 全家桶中,Spring Cloud Feign 則是更常見的選擇。那么,我如何只使用 Spring Cloud Feign 而不引入整個 Spring Cloud 呢?

什么是Feign?

Feign是一個聲明式的Web Service客戶端,它的目的就是讓Web Service調用更加簡單。Feign提供了HTTP請求的模板,通過編寫簡單的接口和插入注解,就可以定義好HTTP請求的參數、格式、地址等信息。

而Feign則會完全代理HTTP請求,我們只需要像調用方法一樣調用它就可以完成服務請求及相關處理。Feign整合了Ribbon和Hystrix,可以讓我們不再需要顯式地使用這兩個組件。

總起來說,Feign具有如下特性:

  • 可插拔的注解支持,包括Feign注解和JAX-RS注解;
  • 支持可插拔的HTTP編碼器和解碼器;
  • 支持Hystrix和它的Fallback;
  • 支持Ribbon的負載均衡;
  • 支持HTTP請求和響應的壓縮。

這看起來有點像我們springmvc模式的Controller層的RequestMapping映射。這種模式是我們非常喜歡的。Feign是用@FeignClient來映射服務的。

首先找一個AIP

免費的API特別多,github上也有免費API地址匯總的repo,但這些都太正式了。有趣的事物總是會相互吸引的,無意間我發現了這么一個網站,“渣男:說話的藝術”(lovelive.tools) ,每次請求都可以獲取一句甜言蜜語(渣男語錄),特別良心的是,作者提供了API列表,給作者點贊!

如何調用第三方服務?

首先,我們先快速構建一個 Spring Boot 的 web 項目,這里我就省略了。然后在pom中添加feign的相關依賴

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-openfeign</artifactId>
     <version>2.1.3.RELEASE</version>
</dependency>

然后,在啟動類添加響應的注解 @EnableFeignClients:

@SpringBootApplication
@EnableFeignClients
public class SpringbootMiddlewareFeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringbootMiddlewareFeignApplication.class, args);
    }
}

接着,我們便可以配置我們的 Client 了,我們先創建一個接口類,比如叫BadGuyFeignClient ,並聲明為 FeignClient:

@FeignClient
public interface BadGuyFeignClient {

}

@FeignClient有以下幾個較常用屬性:

屬性名 默認值 作用 備注
value 空字符串 調用服務名稱,和name屬性相同,如果項目使用了 Ribbon,name屬性會作為微服務的名稱,用於服務發現;  
serviceId 空字符串 服務id,作用和name屬性相同 已過期
name 空字符串 調用服務名稱,和value屬性相同,如果項目使用了 Ribbon,name屬性會作為微服務的名稱,用於服務發現;  
url 空字符串 url一般用於調試,可以手動指定@FeignClient調用的地址  
decode404 false 配置響應狀態碼為404時是否應該拋出FeignExceptions  
configuration {} Feign配置類,可以自定義 Feign的 Encoder、Decoder、LogLevel、Contract; 參考FeignClientsConfiguration
fallback void.class 定義容錯的處理類,當調用遠程接口失敗或超時時,會調用對應接口的容錯邏輯,fallback指定的類必須實現@FeignClient標記的接口 底層依賴hystrix,啟動類要加上@EnableHystrix
fallbackFactory void.class 工廠類,用於生成fallback類示例,通過這個屬性我們可以實現每個接口通用的容錯邏輯,減少重復的代碼  
path 空字符串 自動給所有方法的requestMapping前加上前綴,類似與controller類上的requestMapping  

然后,我們便可以配置對應的屬性,這里我們只是用來實現類似於 HTTP Client 的功能,所以只是簡單配置了url和path這些屬性:

@FeignClient(name = "badGuy", url = "${bab.guy.url}", path = "api")
public interface BadGuyFeignClient {

    /**
     * 隨機獲取一句甜言蜜語
     *
     * @return
     */
    @GetMapping("SweetNothings")
    String getSweetNothings();

    /**
     * 獲取 count 條甜言蜜語
     *
     * @param count 獲取甜言蜜語條數
     * @return Json 格式的結果
     */
    @GetMapping("SweetNothings/{count}/Serialization/Json")
    ReturnResult<List<String>> getSweetNothingsJsonByCount(@PathVariable("count") Integer count);

}

聲明為FeignClient之后,我們便可以在代碼中使用@Resource或者@Autowire進行注入使用了:

提示 org.apache.http.impl.client.HttpClientBuilder 這個類找不到 問題的解決

java.lang.IllegalStateException: Error processing condition on org.springframework.cloud.commons.httpclient.HttpClientConfiguration$ApacheHttpClientConfiguration.apacheHttpClientBuilder
	at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:60) ~[spring-boot-autoconfigure-2.3.3.RELEASE.jar:2.3.3.RELEASE]
	......
	
Caused by: java.lang.IllegalStateException: @ConditionalOnMissingBean did not specify a bean using type, name or annotation and the attempt to deduce the bean's type failed
	at org.springframework.boot.autoconfigure.condition.OnBeanCondition$Spec.validate(OnBeanCondition.java:487) ~[spring-boot-autoconfigure-2.3.3.RELEASE.jar:2.3.3.RELEASE]
	......
	... 18 common frames omitted
Caused by: org.springframework.boot.autoconfigure.condition.OnBeanCondition$BeanTypeDeductionException: Failed to deduce bean type for org.springframework.cloud.commons.httpclient.HttpClientConfiguration$ApacheHttpClientConfiguration.apacheHttpClientBuilder
	......
	... 20 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.apache.http.impl.client.HttpClientBuilder
	......
	... 22 common frames omitted

2021-03-15 07:34:52.548  WARN 11915 --- [           main] o.s.boot.SpringApplication               : Unable to close ApplicationContext

java.lang.IllegalStateException: Failed to introspect Class [org.springframework.cloud.commons.httpclient.HttpClientConfiguration$ApacheHttpClientConfiguration] from ClassLoader [sun.misc.Launcher$AppClassLoader@18b4aac2]
	at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:481) ~[spring-core-5.2.8.RELEASE.jar:5.2.8.RELEASE]
	......
Caused by: java.lang.NoClassDefFoundError: org/apache/http/impl/client/HttpClientBuilder
	at java.lang.Class.getDeclaredMethods0(Native Method) ~[na:1.8.0_241]
	......
	... 21 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.apache.http.impl.client.HttpClientBuilder
	at java.net.URLClassLoader.findClass(URLClassLoader.java:382) ~[na:1.8.0_241]
	......
	... 25 common frames omitted


Process finished with exit code 1

 這是springcloud 中的依賴,我們發現在這里有兩個不同版本的httpclient, 盲猜是低版本的依賴中沒有那個類所以與springboot 項目不兼容。打開目錄結構果然沒有發現 httpClientBuilder 這個類。

 引入httpclient 的版本即可

<properties>
   <httpclient.version>4.5</httpclient.version>
</properties>
<dependencyManagement>
   <dependencies>
       <dependency>
           <groupId>org.apache.httpcomponents</groupId>
           <artifactId>httpclient</artifactId>
           <version>${httpclient.version}</version>
       </dependency>
   </dependencies>
</dependencyManagement>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM