在使用 SpringCloud 時短蜕,遠程服務都是以 HTTP 接口形式對外提供服務氢架,因此服務消費者在調(diào)用服務時,需要使用 HTTP Client 方式訪問朋魔。在通常進行遠程 HTTP 調(diào)用時岖研,可以使用 RestTemplate、HttpClient警检、URLConnection孙援、OkHttp 等,也可以使用 SpringCloud Feign 進行遠程調(diào)用
RestTemplate
源碼:https://gitee.com/laiyy0728/spring-cloud/tree/master/spring-cloud-feign/spring-cloud-feign-simple
脫離 Eureka 的使用
在脫離 Eureka 使用 RestTemplate 調(diào)用遠程接口時扇雕,只需要引入 web 依賴即可拓售。
在使用 RestTemplate 時,需要先將 RestTemplate 交給 Spring 管理
@Configuration
public class RestTemplateConfiguration {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
編寫一個 Controller镶奉,注入 RestTemplate础淤,調(diào)用遠程接口
@RestController
public class RestTemplateController {
private final RestTemplate restTemplate;
@Autowired
public RestTemplateController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
@GetMapping(value = "rest-get", produces = "text/html;charset=utf-8")
public String restTemplateGet(){
return restTemplate.getForObject("https://gitee.com", String.class);
}
}
訪問 http://localhost:8080/rest-get
關聯(lián) Eureka 使用
將服務注冊到 Eureka Server,并使用 RestTemplate 調(diào)用遠程 Eureka Client 服務
此時哨苛,只需要按照一個標準的 Eureka Client 編寫步驟鸽凶,將項目改造成一個 Eureka Client,并編寫另外一個 Client建峭。將要使用 RestTemplate 的 Client 當做服務消費者玻侥,另外一個當做服務提供者。在進行遠程調(diào)用時迹缀,只需要將 getForObject
的 url使碾,改為 http://service-id 即可,具體傳入?yún)?shù)使用 ?
祝懂、&
、=
拼接即可拘鞋。
在注冊到 Eureka Server 后砚蓬,進行 RestTemplate 遠程調(diào)用時,service-id 會被 Eureka Client 解析為 Server 中注冊的 ip盆色、端口灰蛙,以此進行遠程調(diào)用。
Rest Template
RestTemplate 提供了 11 個獨立的方法隔躲,這 11 個方法對應了各種遠程調(diào)用請求
方法名 | http 動作 | 說明 |
---|---|---|
getForEntity() | GET | 發(fā)送 GET 請求摩梧,返回的 ResponseEntity 包含了響應體所映射成的對象 |
getForObject() | GET | 發(fā)送 GET 請求,返回的請求體將映射為一個對象 |
postForEntity() | POST | 發(fā)送 POST 請求宣旱,返回包含一個對象的 ResponseEntity仅父,這個對象是從響應體中映射得到的 |
postForObject() | POST | 發(fā)送 POST 請求,返回根據(jù)響應體匹配形成的對象 |
postForLocation() | POST | 發(fā)送 POST 請求,返回新創(chuàng)建資源的 URL |
put() | PUT | PUT 資源到指定 URL |
delete() | DELETE | 發(fā)送 DELETE 請求笙纤,執(zhí)行刪除操作 |
headForHeaders() | HEAD | 發(fā)送 HEAD 請求耗溜,返回包含指定資源 URL 的 HTTP 頭 |
optionsFOrAllow() | OPTIONS | 發(fā)送 OPTIONS 請求,返回指定 URL 的 Allow 頭信息 |
execute() | 執(zhí)行非響應 ResponseEntity 的請求 | |
exchange() | 執(zhí)行響應 ResponseEntity 的請求 |
Feign
使用 RestTemplate 進行遠程調(diào)用省容,非常方便抖拴,但是也有一個致命的問題:硬編碼。 在 RestTemplate 調(diào)用中腥椒,我們每個調(diào)用遠程接口的方法阿宅,都將遠程接口對應的 ip、端口笼蛛,或 service-id 硬編碼到了 URL 中家夺,如果遠程接口的 ip、端口伐弹、service-id 有修改的話拉馋,需要將所有的調(diào)用都修改一遍,這樣難免會出現(xiàn)漏改惨好、錯改等問題煌茴,且代碼不便于維護。為了解決這個問題日川,Netflix 推出了 Feign 來統(tǒng)一管理遠程調(diào)用蔓腐。
什么是 Feign
Feign 是一個聲明式的 Web Service 客戶端,只需要創(chuàng)建一個接口龄句,并加上對應的 Feign Client 注解回论,即可進行遠程調(diào)用。Feign 也支持編碼器分歇、解碼器傀蓉,Spring Cloud Open Feign 也對 Feign 進行了增強,支持了 SpringMVC 注解职抡,可以像 SpringMVC 一樣進行遠程調(diào)用葬燎。
Feign 是一種聲明式、模版化的 HTTP 客戶端缚甩,在 Spring Cloud 中使用 Feign谱净,可以做到使用 HTTP 請求訪問遠程方法就像調(diào)用本地方法一樣簡單,開發(fā)者完全感知不到是在進行遠程調(diào)用擅威。
Feign 的特性:
- 可插拔的注解支持
- 可插拔的 HTTP 編碼器壕探、解碼器
- 支持 Hystrix 斷路器、Fallback
- 支持 Ribbon 負載均衡
- 支持 HTTP 請求郊丛、響應壓縮
簡單示例
源碼:https://gitee.com/laiyy0728/spring-cloud/tree/master/spring-cloud-feign/spring-cloud-feign-simple
使用 Feign 進行 github 接口調(diào)用
pom 依賴
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
配置文件
只是進行一個簡單的遠程調(diào)用李请,不需要注冊 Eureka瞧筛、不需要配置文件。
啟動類
@SpringBootApplication
@EnableFeignClients
public class SpringCloudFeignSimpleApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCloudFeignSimpleApplication.class, args);
}
}
Feign Client 配置
@Configuration
public class GiteeFeignConfiguration {
/**
* 配置 Feign 日志級別
* <p>
* NONE:沒有日志
* BASIC:基本日志
* HEADERS:header
* FULL:全部
* <p>
* 配置為打印全部日志捻艳,可以更方便的查看 Feign 的調(diào)用信息
*
* @return Feign 日志級別
*/
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
FeignClient
@FeignClient(name = "gitee-client", url = "https://www.gitee.com/", configuration = GiteeFeignConfiguration.class)
public interface GiteeFeignClient {
@RequestMapping(value = "/search", method = RequestMethod.GET)
String searchRepo(@RequestParam("q") String query);
}
@FeignClient
:聲明為一個 Feign 遠程調(diào)用
name
:給遠程調(diào)用起個名字
url
:指定要調(diào)用哪個 url
configuration
:指定配置信息
@RequestMapping
:如同 SpringMVC 一樣調(diào)用驾窟。
Feign Controller
@RestController
public class FeignController {
private final GiteeFeignClient giteeFeignClient;
@Autowired
public FeignController(GiteeFeignClient giteeFeignClient) {
this.giteeFeignClient = giteeFeignClient;
}
@GetMapping(value = "feign-gitee")
public String feign(String query){
return giteeFeignClient.searchRepo(query);
}
}
驗證調(diào)用結果
在瀏覽器中訪問: http://localhost:8080/feign-gitee?query=spring-cloud-openfeign
@FeignClient、@RequestMapping
在 Feign 中使用 MVC 注解的注意事項
在 FeignClient 中使用 @RequestMapping
注解調(diào)用遠程接口认轨,需要注意:
- 注解必須為
@RequestMapping
绅络,不能為組合注解@GetMapping
等,否則解析不到 - 必須指定 method嘁字,否則會出問題
- value 必須指定被調(diào)用方的 url恩急,不能包含域名、ip 等
使用 @FeignClient 的注意事項
- 在啟動類上必須加上
@FeignClients
注解纪蜒,開啟掃描 - 在 FeignClient 接口上必須指定
@FeignClient
注解衷恭,聲明是一個 Feign 遠程調(diào)用
@FeignClient
源碼
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
@AliasFor("name")
String value() default "";
/** @deprecated */
@Deprecated
String serviceId() default "";
@AliasFor("value")
String name() default "";
String qualifier() default "";
String url() default "";
boolean decode404() default false;
Class<?>[] configuration() default {};
Class<?> fallback() default void.class;
Class<?> fallbackFactory() default void.class;
String path() default "";
boolean primary() default true;
}
字段名 | 含義 |
---|---|
name | 指定 FeignClient 的名稱,如果使用到了 Eureka纯续,且使用了 Ribbon 負載均衡随珠,則 name 為被調(diào)用者的微服務名稱,用于服務發(fā)現(xiàn) |
url | 一般用于調(diào)試猬错,可以手動指定 feign 調(diào)用的地址 |
decode404 | 當 404 時窗看,如果該字段為 true,會調(diào)用 decoder 進行解碼倦炒,否則會拋出 FeignException |
configuration | Feign 配置類显沈,可以自定義 Feign 的 Encoder、Decoder逢唤、LogLevel拉讯、Contract 等 |
fallback | 容錯處理類,當遠程調(diào)用失敗鳖藕、超時時魔慷,會調(diào)用對應接口的容錯邏輯。Fallback 指定的類吊奢,必須實現(xiàn) @FeignClient 標記的接口 |
fallbackFactory | 工廠類盖彭,用于生成 fallback 類的示例,可以實現(xiàn)每個接口通用的容錯邏輯页滚,減少重復代碼 |
path | 定義當前 FeignClient 的統(tǒng)一前綴 |
Feign 的運行原理
- 在啟動類上加上
@EnableFeignClients
注解,開啟對 Feign Client 掃描加載 - 在啟用時铺呵,會進行包掃描裹驰,掃描所有的
@FeignClient
的注解的類,并將這些信息注入 Spring IOC 容器片挂,當定義的 Feign 接口中的方法被調(diào)用時幻林,通過 JDK 的代理方式贞盯,來生成具體的RestTemplate
。當生成代理時沪饺,F(xiàn)eign 會為每個接口方法創(chuàng)建一個RestTemplate
對象躏敢,該對象封裝了 HTTP 請求需要的全部信息,如:參數(shù)名整葡、請求方法件余、header等 - 然后由
RestTemplate
生成 Request,然后把 Request 交給 Client 處理遭居,這里指的 Client 可以是 JDK 原生的URLConnection
啼器、Apache 的HTTP Client
、OkHttp
俱萍。最后 Client 被封裝到 LoadBalanceClient 類端壳,結合 Ribbon 負載均衡發(fā)起服務間的調(diào)用。