介紹
微服務(wù)橫行的互聯(lián)網(wǎng)世界, 跨服務(wù)調(diào)用顯得很平凡, 我們除了采用傳統(tǒng)的http方式接口調(diào)用, 有沒有更為優(yōu)雅方便的方法呢?
答案是肯定的,feign就提供了輕便的方式!
如果你的服務(wù)都注冊了注冊中心,比如nacos, 那么調(diào)用會顯得很輕松, 只需一個(gè)注解, 帶上需要調(diào)用的服務(wù)名即可,feign + nacos
會幫你做剩余的事.
如果沒有注冊中心, 也無需擔(dān)心, feign一樣可以以傳統(tǒng)的
ip:port
方式進(jìn)行調(diào)用~
下面,我們來實(shí)踐下吧
springboot整合feign
引入依賴, 這里注意, spring-cloud.version記得要和spring-boot版本匹配, 我這里spring-boot版本是2.1.3, 所以spring-cloud選擇Greenwich.SR2版本.
大致的版本對應(yīng)關(guān)系如下
更詳細(xì)的請去https://start.spring.io/actuator/info
查詢!
<properties>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<!--SpringCloud依賴 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--openfeign跨服務(wù)調(diào)用-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--openfeign底層使用ApacheHttpClient調(diào)用-->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
</dependencies>
然后我們?nèi)ロ?xiàng)目的啟動類上加上注解
@EnableFeignClients
最后, 加上Feign的配置
application.properties
server.port=9999
#******************openfeign配置,參數(shù)采用的是默認(rèn)的配置看疙,可根據(jù)實(shí)際情況調(diào)整***********************
#啟用ApacheHttpClient豆拨。默認(rèn)就是true,使用HttpClientConnectionManager管理連接復(fù)用
feign.httpclient.enabled=true
#連接池的最大連接數(shù)能庆,默認(rèn)200
feign.httpclient.max-connections=200
#每個(gè)路由(服務(wù)器)分配的組最大連接數(shù)施禾,默認(rèn)50
feign.httpclient.max-connections-per-route=50
#連接最大存活時(shí)間,默認(rèn)900秒
feign.httpclient.time-to-live=900
#連接最大存活時(shí)間單位秒
feign.httpclient.time-to-live-unit=seconds
#FeignAcceptGzipEncodingInterceptor攔截器被激活搁胆,會在header中添加Accept-Encoding:gzip,deflate,表明服務(wù)端在返回值時(shí)可以使用如下兩個(gè)方式壓縮返回結(jié)果
feign.compression.response.enabled=true
#FeignContentGzipEncodingInterceptor攔截器被激活弥搞,會在header中添加Content-Encoding:gzip,deflate,表明body中的參數(shù)是使用這兩個(gè)方式的壓縮
feign.compression.request.enabled=true
#content-length大于2048就進(jìn)行請求參數(shù)的gzip壓縮
feign.compression.request.minRequestSize=2048
#開啟斷路器
feign.hystrix.enabled=true
#斷路器的隔離策略邮绿,默認(rèn)就是線程池,SEMAPHORE模式下攀例,就是主線程調(diào)用的遠(yuǎn)程的服務(wù)船逮,即同步的
hystrix.command.default.execution.isolation.strategy=THREAD
#斷路器超時(shí)設(shè)置
hystrix.command.default.execution.timeout.enabled=true
#總體請求在45秒還是無法得到響應(yīng),建議觸發(fā)熔斷(ribbon每個(gè)請求讀取15秒超時(shí)粤铭,兩個(gè)實(shí)例重試就是30秒傻唾,openfeign外層默認(rèn)會進(jìn)行一次調(diào)用,4次重試)
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=45000
#斷路器的線程池存在一個(gè)問題承耿,在隊(duì)列滿了以后,不會再去創(chuàng)建新的線程直到maximumSize
#核心線程池大小
hystrix.threadpool.default.coreSize=10
#最大線程池大小
hystrix.threadpool.default.maximumSize=10
#超過這個(gè)空閑時(shí)間,多于coreSize數(shù)量的線程會被回收伪煤,1分鐘
hystrix.threadpool.default.keepAliveTimeMinutes=1
#隊(duì)列的大小加袋,默認(rèn)為-1,即沒有隊(duì)列
hystrix.threadpool.default.maxQueueSize=200
#隊(duì)列任務(wù)達(dá)到此閾值后抱既,就開始拒絕职烧;實(shí)際使用此參數(shù)進(jìn)行隊(duì)列是否滿的判斷
hystrix.threadpool.default.queueSizeRejectionThreshold=180
#負(fù)載均衡配置
#讀取超時(shí)15秒,與原RestTemplate保持一致
ribbon.ReadTimeout=15000
#連接超時(shí)15秒防泵,與原RestTemplate保持一致
ribbon.ConnectTimeout=15000
##每臺服務(wù)器最多重試次數(shù)蚀之,但是首次調(diào)用不包括在內(nèi)
ribbon.MaxAutoRetries=0
##最多重試多少臺服務(wù)器,與實(shí)際實(shí)例數(shù)保持一致(不包括首臺)
ribbon.MaxAutoRetriesNextServer=1
#是否所有操作都重試,
# false:get請求中捷泞,連接超時(shí)足删,讀取超時(shí)都會重試,其他請求(put,post)連接超時(shí)重試锁右,讀取超時(shí)不重試失受。
# true:get請求中,連接超時(shí)咏瑟,讀取超時(shí)都會重試拂到,其他請求(put,post)連接超時(shí)重試,讀取超時(shí)重試码泞。
#對于請求(put,post)要做好接口的冪等性
ribbon.OkToRetryOnAllOperations=true
spring-boot整合feign完成, 接下來我們編寫測試代碼
測試代碼
兩個(gè)服務(wù)
sb-alibaba-nacos (被調(diào)用方服務(wù), 127.0.0.1:8081), 提供 getInfoById接口
sb-feign (調(diào)用方服務(wù), 127.0.0.1:9999), 提供 getInfoById 測試接口
sb-alibaba-nacos提供的測試接口
@GetMapping(value = "getInfoById")
public String getInfoById(@RequestParam(value = "id") Long Id) {
return "example-service return :" + Id;
}
sb-feign相關(guān)代碼
我們新建個(gè)包 feign,用來放所有涉及跨服務(wù)調(diào)用的類
ExampleControllerFeignClient.java:
package com.mrcoder.sbfeign.feign;
import feign.hystrix.FallbackFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(name = "sb-alibaba-nacos", url = "http://127.0.0.1:8081/", fallbackFactory = ExampleControllerFeignClient.ExampleControllerFeignClientFallbackFactory.class)
public interface ExampleControllerFeignClient {
@GetMapping(value = "getInfoById")
String getInfoById(@RequestParam(value = "id") Long Id);
/**
* 服務(wù)降級內(nèi)部類
*/
@Component
class ExampleControllerFeignClientFallbackFactory implements FallbackFactory<ExampleControllerFeignClient> {
private Logger logger = LoggerFactory.getLogger(ExampleControllerFeignClientFallbackFactory.class);
@Override
public ExampleControllerFeignClient create(Throwable cause) {
return new ExampleControllerFeignClient() {
@Override
public String getInfoById(Long signingLogId) {
logger.error("跨服務(wù)調(diào)用失敗兄旬, 原因是:" + cause.getMessage());
return "失敗, 原因是:" + cause.getMessage();
}
};
}
}
}
關(guān)鍵代碼就是
@FeignClient(name = "sb-alibaba-nacos", url = "http://127.0.0.1:8081/", fallbackFactory = ExampleControllerFeignClient.ExampleControllerFeignClientFallbackFactory.class)
name 就是被調(diào)用方的服務(wù)名稱 (
這里如果你沒有配置服務(wù)注冊中心的化,其實(shí)可以隨便寫
)url 就是被調(diào)用方的地址(
如果配置了服務(wù)注冊中心, 可以不寫!, 不過兩個(gè)服務(wù)必須都注冊!,這樣才能找到!
)fallbackFactory 就是調(diào)用失敗時(shí)指定的處理類
最后, 我們寫個(gè)測試方法
package com.mrcoder.sbfeign.controller;
import com.mrcoder.sbfeign.feign.ExampleControllerFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@CrossOrigin
@RestController
public class TestController {
@Autowired
private ExampleControllerFeignClient exampleControllerFeignClient;
@RequestMapping(value = "getInfoById", method = RequestMethod.GET)
public String test(@RequestParam(value = "id") Long Id) {
return exampleControllerFeignClient.getInfoById(Id);
}
}
開啟兩個(gè)服務(wù)sb-alibaba-nacos, sb-feign
而后訪問sb-feign的測試方法
http://localhost:9999/getInfoById?id=22
出現(xiàn)
sb-alibaba-nacos return :22
跨服務(wù)調(diào)用成功~
項(xiàng)目地址
https://github.com/MrCoderStack/SpringBootDemo/tree/master/sb-feign