SpringCloud之服務(wù)提供與調(diào)用(Ribbon,Feign)

本系列介紹的配置均基于 Spring Boot 2.0.1.RELEASE 版本和 Spring Cloud Finchley.SR1

eureka注冊續(xù)約流程

啟動注冊中心

服務(wù)提供者生產(chǎn)服務(wù)并注冊到服務(wù)中心中

消費者從服務(wù)中心中獲取服務(wù)并執(zhí)行

服務(wù)提供

1.在spring-cloud-manage下創(chuàng)建一個子項目producer-service

pom.xml文件如下

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"

? ? ? ? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

? ? ? ? xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

? ? <parent>

? ? ? ? <artifactId>spring-cloud-manage</artifactId>

? ? ? ? <groupId>org.springcloudmanage</groupId>

? ? ? ? <version>1.0</version>

? ? </parent>

? ? <modelVersion>4.0.0</modelVersion>

? ? <artifactId>producer-service</artifactId>

? ? <properties>

? ? ? ? <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

? ? ? ? <maven.compiler.source>1.8</maven.compiler.source>

? ? ? ? <maven.compiler.target>1.8</maven.compiler.target>

? ? </properties>

? ? <dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-web</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.cloud</groupId>

? ? ? ? ? ? <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

? ? ? ? </dependency>

? ? </dependencies>

? ? <build>

? ? ? ? <finalName>producer-service</finalName>

? ? ? ? <plugins>

? ? ? ? ? ? <plugin>

? ? ? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? ? ? <artifactId>spring-boot-maven-plugin</artifactId>

? ? ? ? ? ? </plugin>

? ? ? ? </plugins>

? ? </build>

</project>

2.創(chuàng)建啟動類

Finchley版本已經(jīng)不需要添加@EnableDiscoveryClient注解,Spring Cloud會自動識別。

@SpringBootApplication

public class ProducerServiceApplication {

? ? public static void main(String[] args) {

? ? ? ? SpringApplication.run(ProducerServiceApplication.class, args);

? ? }

}

3.配置文件

spring.application.name=producer-service

server.port=9001

#eureka

eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/

spring.application.name服務(wù)提供者的名字

server.por服務(wù)端口號

eureka.client.serviceUrl.defaultZoneeureka的服務(wù)注冊地址,如果eureka是多節(jié)點,多個地址逗號分隔,具體可以看上一篇博客:服務(wù)注冊與發(fā)現(xiàn)。

多節(jié)點eureka服務(wù)注冊如下:

eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/,http://localhost:8002/eureka/

4.Action or Controller類

@RestController

@RequestMapping(value = "/test")

public class ProducerAction {

? ? @RequestMapping(value = "", method = RequestMethod.GET)

? ? public String test(String param) {

? ? ? ? return "param is " + param;

? ? }

}

5.啟動服務(wù)

服務(wù)啟動后,訪問eureka主頁http://localhost:8001/,即可看到如下頁面,說明服務(wù)已經(jīng)注冊到eureka上了?

6.調(diào)用下試試

訪問http://localhost:9001/test?param=test,看到返回結(jié)果如下

param is test

服務(wù)消費 ribbon

Ribbon 了,它是一個基于 HTTP 和 TCP 的客戶端負(fù)載均衡器。它可以通過在客戶端中配置ribbonServerList 來設(shè)置服務(wù)端列表去輪詢訪問以達(dá)到均衡負(fù)載的作用。

當(dāng) Ribbon 與 Eureka聯(lián)合使用時,ribbonServerList會被DiscoveryEnabledNIWSServerList 重寫,擴(kuò)展成從 Eureka 注冊中心中獲取服務(wù)實例列表。同時它也會用 NIWSDiscoveryPing 來取代 IPing,它將職責(zé)委托給 Eureka 來確定服務(wù)端是否已經(jīng)啟動。

1.在spring-cloud-manage下創(chuàng)建一個子項目consumer-service

pom.xml文件如下

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

? ? ? ? xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

? ? <parent>

? ? ? ? <artifactId>spring-cloud-manage</artifactId>

? ? ? ? <groupId>org.springcloudmanage</groupId>

? ? ? ? <version>1.0</version>

? ? </parent>

? ? <modelVersion>4.0.0</modelVersion>

? ? <artifactId>consumer-service</artifactId>

? ? <properties>

? ? ? ? <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

? ? ? ? <maven.compiler.source>1.8</maven.compiler.source>

? ? ? ? <maven.compiler.target>1.8</maven.compiler.target>

? ? </properties>

? ? <dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-web</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.cloud</groupId>

? ? ? ? ? ? <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

? ? ? ? </dependency>

? ? </dependencies>

? ? <build>

? ? ? ? <plugins>

? ? ? ? ? ? <plugin>

? ? ? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? ? ? <artifactId>spring-boot-maven-plugin</artifactId>

? ? ? ? ? ? </plugin>

? ? ? ? </plugins>

? ? </build>

</project>

spring-cloud-starter-netflix-eureka-client中已經(jīng)引用了ribbon先關(guān)的jar,所需不需要再引入了

2.創(chuàng)建啟動類

@SpringBootApplication

public class ConsumerServiceApplication {

? ? @LoadBalanced

? ? @Bean

? ? public RestTemplate restTemplate() {

? ? ? ? return new RestTemplate();

? ? }

? ? public static void main(String[] args) {

? ? ? ? SpringApplication.run(ConsumerServiceApplication.class, args);

? ? }

}

3.配置文件

spring.application.name=consumer-service

server.port=9002

#eureka

eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/

4.Action or Controller類

這里注入restTemplate,Spring Cloud Ribbon 自己有攔截器會對 服務(wù)名producer-service做解析,自動的去選取服務(wù)實例負(fù)載均衡調(diào)用,并將服務(wù)名替換成實際要請求的IP地址和端口

@RestController

@RequestMapping(value = "/ribbon/test")

public class ConsumerAction {

? ? @Autowired

? ? private RestTemplate restTemplate;

? ? @RequestMapping(value = "", method = RequestMethod.GET)

? ? public String test(String param) {

? ? ? ? String url = "http://producer-service/test/?param=" + param;

? ? ? ? return restTemplate.getForObject(url, String.class);

? ? }


}

5.啟動服務(wù)

消費端服務(wù)啟動成功后,可以看到erueka時已經(jīng)顯示注冊成功了

5.調(diào)用消費端服務(wù)

訪問http://localhost:9002/ribbon/test?param=ribbon-test?,可以看到如下結(jié)果,說明消費端服務(wù)接收到參數(shù)后,通過ribbon負(fù)載均衡,調(diào)用到producer-service的接口。

param is ribbon-test

控制臺日志

2018-08-28 16:25:23.397? INFO 3791 --- [nio-9002-exec-1] c.netflix.config.ChainedDynamicProperty? : Flipping property: producer-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

2018-08-28 16:25:23.414? INFO 3791 --- [nio-9002-exec-1] c.n.u.concurrent.ShutdownEnabledTimer? ? : Shutdown hook installed for: NFLoadBalancer-PingTimer-producer-service

2018-08-28 16:25:23.433? INFO 3791 --- [nio-9002-exec-1] c.netflix.loadbalancer.BaseLoadBalancer? : Client: producer-service instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=producer-service,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null

2018-08-28 16:25:23.440? INFO 3791 --- [nio-9002-exec-1] c.n.l.DynamicServerListLoadBalancer? ? ? : Using serverListUpdater PollingServerListUpdater

2018-08-28 16:25:23.462? INFO 3791 --- [nio-9002-exec-1] c.netflix.config.ChainedDynamicProperty? : Flipping property: producer-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

2018-08-28 16:25:23.463? INFO 3791 --- [nio-9002-exec-1] c.n.l.DynamicServerListLoadBalancer? ? ? : DynamicServerListLoadBalancer for client producer-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=producer-service,current list of Servers=[192.168.101.238:9001],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]

},Server stats: [[Server:192.168.101.238:9001; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]

]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@12e48993

2018-08-28 16:25:24.447? INFO 3791 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty? : Flipping property: producer-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

可以啟動多個producer-service服務(wù)測試下實際的負(fù)載均衡效果。

服務(wù)消費 feign

Feign是一個聲明式的Web Service客戶端,它使得編寫Web Serivce客戶端變得更加簡單。我們只需要使用Feign來創(chuàng)建一個接口并用注解來配置它既可完成。它具備可插拔的注解支持,包括Feign注解和JAX-RS注解。Feign也支持可插拔的編碼和解碼。Spring Cloud為Feign增加了對Spring MVC注解的支持,還整合了Ribbon和Eureka來提供均衡負(fù)載的HTTP客戶端實現(xiàn)。

在實際工作中,我們基本上都是使用Feign來完成調(diào)用的。我們通過一個例子來展現(xiàn) Feign 如何方便的聲明對 eureka-producer 服務(wù)的定義和調(diào)用。

1.consumer-service添加對feign的依賴

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

? ? ? ? xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

? ? <parent>

? ? ? ? <artifactId>spring-cloud-manage</artifactId>

? ? ? ? <groupId>org.springcloudmanage</groupId>

? ? ? ? <version>1.0</version>

? ? </parent>

? ? <modelVersion>4.0.0</modelVersion>

? ? <artifactId>consumer-service</artifactId>

? ? <properties>

? ? ? ? <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

? ? ? ? <maven.compiler.source>1.8</maven.compiler.source>

? ? ? ? <maven.compiler.target>1.8</maven.compiler.target>

? ? </properties>

? ? <dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-web</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.cloud</groupId>

? ? ? ? ? ? <artifactId>spring-cloud-starter-openfeign</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.cloud</groupId>

? ? ? ? ? ? <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

? ? ? ? </dependency>

? ? </dependencies>

? ? <build>

? ? ? ? <plugins>

? ? ? ? ? ? <plugin>

? ? ? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? ? ? <artifactId>spring-boot-maven-plugin</artifactId>

? ? ? ? ? ? </plugin>

? ? ? ? </plugins>

? ? </build>

</project>

2.啟動類上加上feign所需注解

@EnableFeignClients

@SpringBootApplication

public class ConsumerServiceApplication {

? ? public static void main(String[] args) {

? ? ? ? SpringApplication.run(ConsumerServiceApplication.class, args);

? ? }

}

3.配置文件

spring.application.name=consumer-service

server.port=9002

#eureka

eureka.client.serviceUrl.defaultZone=http://localhost:8001/eureka/

#開啟Hystrix斷路器

feign.hystrix.enabled=true

#斷路器的超時時間需要大于ribbon的超時時間,不然不會觸發(fā)重試,缺省為1000

hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000

4.feign 調(diào)用

創(chuàng)建feign客戶端調(diào)用類,其中name為所需調(diào)用的服務(wù)名,fallback使用Hystrix,當(dāng)producer-service不可用時,對服務(wù)做降級,并返回友好提示

@FeignClient(name = "producer-service", fallback = ProducerServiceFeignClientHystrix.class)

public interface ProducerServiceFeignClient {

? ? @RequestMapping(value = "/test", method = RequestMethod.GET)

? ? String test(@RequestParam("param") String param);

}

==注意@RequestParam("param")中name必須要和producer-service服務(wù)中的參數(shù)名一致==

@Component

public class ProducerServiceFeignClientHystrix implements ProducerServiceFeignClient {

? ? @Override

? ? public String test(String param) {

? ? ? ? return "服務(wù)[producer-service]無法訪問";

? ? }

}

訪問http://localhost:9002/feign/test?param=feign-test,可以看到如下結(jié)果

param is feign-test

停止producer-service,再次訪問http://localhost:9002/feign/test?param=feign-test,可以看到如下結(jié)果,說明fallback已經(jīng)生效了

服務(wù)[producer-service]無法訪問

歡迎工作一到五年的Java工程師朋友們加入Java程序員開發(fā): 721575865

群內(nèi)提供免費的Java架構(gòu)學(xué)習(xí)資料(里面有高可用、高并發(fā)、高性能及分布式、Jvm性能調(diào)優(yōu)、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構(gòu)資料)合理利用自己每一分每一秒的時間來學(xué)習(xí)提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容