您好,登錄后才能下訂單哦!
這篇文章主要講解了基于springcloud模擬RPC調(diào)用的方法,內(nèi)容清晰明了,對(duì)此有興趣的小伙伴可以學(xué)習(xí)一下,相信大家閱讀完之后會(huì)有幫助。
Feign簡(jiǎn)介
Feign是一個(gè)聲明式的Web Service客戶(hù)端,它能夠讓W(xué)eb Service客戶(hù)端的編寫(xiě)變得更加容易(你只需創(chuàng)建一個(gè)接口,并在接口上添加相應(yīng)注解即可)。除了Feign自帶的注解外它還支持JAX-RS注解,SpringCloud又為Feign增加了對(duì)SpringMVC注解的支持,同時(shí)為了能夠使用和Spring Web中默認(rèn)使用的相同的httpMessageConverter,SpringCloud集成了Ribbon和Eureka,用來(lái)在使用Feign時(shí)能夠?yàn)槠涮峁┮粋€(gè)負(fù)載均衡的HTTP客戶(hù)端。
總起來(lái)說(shuō),F(xiàn)eign具有如下特性:
1.可插拔的注解支持,包括Feign注解和JAX-RS注解;
2.支持可插拔的HTTP編碼器和解碼器;
3.支持Hystrix和它的Fallback;
4.支持Ribbon的負(fù)載均衡;
5.支持HTTP請(qǐng)求和響應(yīng)的壓縮。
接下來(lái)我們將通過(guò)對(duì)上一章《客戶(hù)端負(fù)載均衡(Ribbon)》中的 message-center 項(xiàng)目進(jìn)行改造,演示如何使用Feign。
message-center改造
引入Feign依賴(lài)
由于Feign依賴(lài)中默認(rèn)包含了Ribbon,所以只需要在 pom.xml 文件中引入Feign依賴(lài)即可,Ribbon依賴(lài)無(wú)需重復(fù)引入:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.6.RELEASE</version> </parent> <properties> <spring-cloud.version>Finchley.SR2</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- Eureka-Client 依賴(lài) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- Feign 依賴(lài) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <!-- SpringCloud 版本控制依賴(lài) --> <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>
修改啟動(dòng)類(lèi)
在MessageCenterApplication啟動(dòng)類(lèi)上增加@EnableFeignClients注解:
import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableFeignClients public class MessageCenterApplication { public static void main(String[] args) { new SpringApplicationBuilder(MessageCenterApplication.class).web(WebApplicationType.SERVLET).run(args); } }
這里我們?cè)趩?dòng)類(lèi)中增加了@EnableFeignClients注解,用來(lái)開(kāi)啟Feign客戶(hù)端發(fā)現(xiàn)功能。
如果你的Feign客戶(hù)端類(lèi)文件不在Spring的包掃描路徑之中,可以在@EnableFeignClients注解中對(duì)Feign客戶(hù)端的包路徑進(jìn)行指定。
@SpringBootApplication @EnableFeignClients(basePackages = "com.pengjunlee.client.**") public class MessageCenterApplication { public static void main(String[] args) { new SpringApplicationBuilder(MessageCenterApplication.class).web(WebApplicationType.SERVLET).run(args); } }
創(chuàng)建Feign客戶(hù)端
對(duì)外提供服務(wù)的HTTP接口定義在MessageController
@RestController @RequestMapping("/api/v1/msg") public class MessageController { @Value("${server.port}") private String port; /** * 返回一條消息 */ @GetMapping("/get") public String getMsg() { return "This message is sent from port: " + port; } }
接下來(lái),我們?cè)谙M(fèi)端message-center中為它創(chuàng)建一個(gè)Feign客戶(hù)端。新建一個(gè)接口取名MessageServiceClient,并在上面添加@FeignClient注解,完整代碼如下:
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; @FeignClient(name = "message-service") public interface MessageServiceClient { @GetMapping("/api/v1/msg/get") public String getMsg(); }
說(shuō)明:此處@FeignClient注解的name屬性應(yīng)與message-service應(yīng)用的spring.application.name屬性相同,表示為message-service服務(wù)創(chuàng)建一個(gè)Feign客戶(hù)端。接口的映射地址路徑以及接口入?yún)⒍急仨毰cMessageController中的方法完全相同。
調(diào)用Feign客戶(hù)端
接下來(lái),我們來(lái)看一看如何在消費(fèi)端使用創(chuàng)建好的Feign客戶(hù)端對(duì)message-service服務(wù)進(jìn)行調(diào)用,示例代碼如下:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.pengjunlee.service.MessageServiceClient; @RestController @RequestMapping("/api/v1/center") public class MessageCenterController { @Autowired private MessageServiceClient messageService; @GetMapping("/msg/get") public Object getMsg() { String msg = messageService.getMsg(); return msg; } }
啟動(dòng)應(yīng)用,再次請(qǐng)求 http://localhost:8781/api/v1/center/msg/get ,返回如下結(jié)果表明服務(wù)調(diào)用成功:
關(guān)于傳參
Feign除了支持自帶的注解和JAX-RS注解外,還支持 SpringMVC注解,常用的有:@RequestParam 、@PathVariable、@RequestBody 等。
例如,服務(wù)端提供如下兩個(gè)服務(wù)接口:
/** * 獲取消息詳情 */ @GetMapping("/api/v1/msg/detail/{id}") public MessageEntity getDetail(@PathVariable(name = "id") Long id) { return messageService.getById(id); } /** * 新建一條消息 */ @PostMapping("/api/v1/msg/save") public MessageEntity save(@RequestBody MessageEntity message) { return messageService.save(message); }
相應(yīng)的,在Feign客戶(hù)端中可以進(jìn)行如下定義:
/** * 獲取消息詳情 */ @GetMapping("/api/v1/msg/detail/{id}") public MessageEntity getDetail(@PathVariable(name = "id") Long id) ; /** * 新建一條消息 */ @PostMapping("/api/v1/msg/save") public MessageEntity save(@RequestBody MessageEntity message) ;
重寫(xiě)Feign的默認(rèn)配置
在Spring Cloud對(duì)Feign的支持實(shí)現(xiàn)中,一個(gè)核心的概念就是客戶(hù)端命名,每一個(gè)Feign客戶(hù)端都是整個(gè)組件系統(tǒng)的一部分,它們相互協(xié)同一起工作來(lái)按照需求與遠(yuǎn)程服務(wù)器取得聯(lián)系。并且它們每一個(gè)都有自己的名字,應(yīng)用程序開(kāi)發(fā)人員可以使用@feignclient來(lái)給它取名。Spring Cloud按照自己的需要又使用FeignClientsConfiguration為每一個(gè)已命名的客戶(hù)端創(chuàng)建了一個(gè)ApplicationContext,額外包含了一個(gè)feign.Decoder、一個(gè) feign.Encoder 和一個(gè) feign.Contract。你可以通過(guò)指定@FeignClient注解的contextId 屬性來(lái)設(shè)置ApplicationContext的名字。
SpringCloud還允許你在FeignClientsConfiguration的基礎(chǔ)之上使用@FeignClient聲明一些額外的配置,從而實(shí)現(xiàn)對(duì)Feign客戶(hù)端的完全控制,如下例所示:
@FeignClient(name = "message-service", configuration = MessageConfiguration.class) public interface MessageServiceClient { //.. }
在這個(gè)例子中,這個(gè)Feign客戶(hù)端將由FeignClientsConfiguration 和MessageConfiguration中的組件一起組成(后者會(huì)覆蓋前者的配置)。
注意:本例中,MessageConfiguration不必用@Configuration注解進(jìn)行標(biāo)注,如果確實(shí)要加上@Configuration注解,你需要注意把MessageConfiguration排除在@ComponentScan和@SpringBootApplication掃描的包路徑之外,否則它將成為feign.Decoder、feign.Encoder 和 feign.Contract 等的默認(rèn)值。
下表列出了 Spring Cloud Netflix 缺省為Feign提供的所有 Bean(Bean類(lèi)型 Bean名稱(chēng):Bean實(shí)現(xiàn)):
Decoder feignDecoder: ResponseEntityDecoder (包裝了一個(gè) SpringDecoder)
Encoder feignEncoder: SpringEncoder
Logger feignLogger: Slf4jLogger
Contract feignContract: SpringMvcContract
Feign.Builder feignBuilder: HystrixFeign.Builder
Client feignClient: 啟用 Ribbon 時(shí)是 LoadBalancerFeignClient,否則使用 feign.Client.Default。
你可以使用 OkHttpClient 或者 ApacheHttpClient 的Feign客戶(hù)端,只需要將 feign.okhttp.enabled 或者 feign.httpclient.enabled 設(shè)置為 true ,并將相應(yīng)類(lèi)添加到項(xiàng)目的CLASSPATH即可。你也可以使用自定義的HTTP 客戶(hù)端,使用 Apache 時(shí)提供一個(gè)ClosableHttpClient 類(lèi)型Bean或者使用OK HTTP時(shí)提供一個(gè)OkHttpClient 類(lèi)型Bean。
默認(rèn)情況下,Spring Cloud Netflix 并沒(méi)有為Feign提供下列的Bean,但依然會(huì)從Spring容器中查找這些類(lèi)型的Bean用來(lái)創(chuàng)建Feign客戶(hù)端。
Logger.Level
Retryer
ErrorDecoder
Request.Options
Collection<RequestInterceptor>
SetterFactory
創(chuàng)建這些類(lèi)型的一個(gè)Bean 并將它寫(xiě)到 @FeignClient 聲明的配置中,這樣你就能夠?qū)@些Bean中的每一個(gè)進(jìn)行重寫(xiě)。例如下面的 MessageConfiguration 利用feign.Contract.Default替代了SpringMvcContract 并向RequestInterceptor 集合中添加了一個(gè)RequestInterceptor 。
@Configuration public class MessageConfiguration { @Bean public Contract feignContract() { return new feign.Contract.Default(); } @Bean public BasicAuthRequestInterceptor basicAuthRequestInterceptor() { return new BasicAuthRequestInterceptor("user", "password"); } }
當(dāng)然,@FeignClient 也支持通過(guò)配置文件進(jìn)行配置。
feign:
client:
config:
message-service:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: full
errorDecoder: com.pengjunlee.SimpleErrorDecoder
retryer: com.pengjunlee.SimpleRetryer
requestInterceptors:
- com.pengjunlee.FooRequestInterceptor
- com.pengjunlee.BarRequestInterceptor
decode404: false
encoder: com.pengjunlee.SimpleEncoder
decoder: com.pengjunlee.SimpleDecoder
contract: com.pengjunlee.SimpleContract
默認(rèn)配置可以通過(guò)@EnableFeignClients的defaultConfiguration屬性進(jìn)行指定,然后會(huì)被應(yīng)用到所有的Feign客戶(hù)端。如果你希望使用配置文件對(duì)所有的@FeignClient進(jìn)行配置,可以使用 default 作為Feign客戶(hù)端的名稱(chēng)。
feign: client: config: default: connectTimeout: 5000 readTimeout: 5000 loggerLevel: basic
如果我們同時(shí)使用了@Configuration Bean和文件配置,文件配置會(huì)優(yōu)先生效。如果你希望優(yōu)先使用 @Configuration Bean中的配置,可以將 feign.client.default-to-properties 設(shè)置為 false 。
如果你需要在RequestInterceptor中使用ThreadLocal 變量,你需要將Hystrix 的線程隔離策略設(shè)置為 SEMAPHORE 或者直接禁用Hystrix 。
# To disable Hystrix in Feign feign: hystrix: enabled: false # To set thread isolation to SEMAPHORE hystrix: command: default: execution: isolation: strategy: SEMAPHORE
關(guān)于超時(shí)
在啟用Ribbon的情況下,F(xiàn)eign客戶(hù)端是一個(gè)LoadBalancerFeignClient Bean,其內(nèi)部有一個(gè) execute() 方法用來(lái)發(fā)送一個(gè)HTTP請(qǐng)求并獲取響應(yīng), 本質(zhì)上其實(shí)還是使用的Ribbon做負(fù)載均衡,并使用RestTemplate發(fā)送的請(qǐng)求。execute() 接口聲明如下:
public Response execute(Request request, Request.Options options) throws IOException;
其中,Request 用來(lái)封裝HTTP請(qǐng)求的詳細(xì)信息。
/** * * An immutable request to an http server. * */ public final class Request { private final String method; private final String url; private final Map<String, Collection<String>> headers; private final byte[] body; private final Charset charset; // ... }
Options 則封裝了一些請(qǐng)求控制參數(shù):
public static class Options { private final int connectTimeoutMillis; private final int readTimeoutMillis; private final boolean followRedirects; public Options(int connectTimeoutMillis, int readTimeoutMillis) { this(connectTimeoutMillis, readTimeoutMillis, true); } public Options() { this(10 * 1000, 60 * 1000); } // ... }
從Options 源碼來(lái)看,F(xiàn)eign客戶(hù)端默認(rèn)的讀取超時(shí)時(shí)間為60秒。若同時(shí)使用了Hystrix,由于Hystrix 默認(rèn)的讀取超時(shí)時(shí)間為1秒,會(huì)導(dǎo)致Feign客戶(hù)端默認(rèn)的讀取超時(shí)時(shí)間設(shè)置無(wú)效,即超過(guò)1秒即為讀取超時(shí)??墒褂萌缦屡渲猛瑫r(shí)對(duì)Feign客戶(hù)端和Hystrix 的超時(shí)配置進(jìn)行重寫(xiě)。
feign: client: config: default: connectTimeout: 5000 readTimeout: 5000
看完上述內(nèi)容,是不是對(duì)基于springcloud模擬RPC調(diào)用的方法有進(jìn)一步的了解,如果還想學(xué)習(xí)更多內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。