目錄
在上一篇文章,講了服務的註冊和發現。在微服務架構中,業務都會被拆分成一個獨立的服務,服務與服務的通訊是基於http restful的。Spring cloud有兩種服務調用方式,一種是ribbon+restTemplate,另一種是feign。在這一篇文章首先講解下基於ribbon+rest。
一、ribbon簡介
Ribbon is a client side load balancer which gives you a lot of control over the behaviour of HTTP and TCP clients. Feign already uses Ribbon, so if you are using @FeignClient then this section also applies.
—–摘自官網
ribbon是一個負載均衡客戶端,可以很好的控制htt和tcp的一些行爲。Feign默認集成了ribbon。
下表顯示了Spring Cloud Netflix默認爲Ribbon提供的bean:
Bean Type | Bean Name | Class Name |
---|---|---|
IClientConfig | ribbonClientConfig | DefaultClientConfigImpl |
IRule | ribbonRule | ZoneAvoidanceRule |
IPing | ribbonPing | DummyPing |
ServerList< server > | ribbonServerList | ConfigurationBasedServerList |
ServerListFilter< Server > | ribbonServerListFilter | ZonePreferenceServerListFilter |
ILoadBalancer | ribbonLoadBalancer | ZoneAwareLoadBalancer |
ServerListUpdater | ribbonServerListUpdater | PollingServerListUpdater |
二、準備工作
這一篇文章基於上一篇文章的工程,啓動eurekaserver 工程;啓動serviceclient工程,它的端口爲8762;將serviceclient的配置文件的端口改爲8763,並啓動,這時你會發現:serviceclient在eurekaserver註冊了2個實例,這就相當於一個小的集羣。訪問localhost:8761如圖所示:
三、建一個服務消費者
重新新建一個spring-boot工程,取名爲:serviceribbon;
在它的pom.xml文件分別引入起步依賴spring-cloud-starter-netflix-eureka-client、spring-cloud-starter-netflix-ribbon、spring-boot-starter-web,代碼如下:
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.springcloud</groupId>
<artifactId>ServiceRibbon</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>ServiceRibbon</name>
<description>Demo project for Spring cloud ribbon</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR1</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<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>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
在工程的配置文件指定服務的註冊中心地址爲http://localhost:8761/eureka/,程序名稱爲 service-ribbon,程序端口爲8764。配置文件application.yml如下:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8764
spring:
application:
name: ServiceRibbon
application.properties配置如下:
eureka. client.serviceUrl.defaultZone=http://localhost:8761/eureka/
server.port=8764
spring.application.name=ServiceRibbon
在工程的啓動類中,通過@EnableDiscoveryClient向服務中心註冊;並且向程序的ioc注入一個bean: restTemplate;並通過@LoadBalanced註解表明這個restRemplate開啓負載均衡的功能。
package com.springcloud.eurekaribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
寫一個測試類HelloService,通過之前注入ioc容器的restTemplate來消費eurekaclient服務的“/hi”接口,在這裏我們直接用的程序名替代了具體的url地址,在ribbon中它會根據服務名來選擇具體的服務實例,根據服務實例在請求的時候會用具體的url替換掉服務名,代碼如下:
package com.springcloud.eurekaribbon.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
public String hiService(String name) {
return restTemplate.getForObject("http://eurekaclient/hi?name="+name,String.class);
}
}
寫一個controller,在controller中用調用HelloService 的方法,代碼如下:
package com.springcloud.eurekaribbon.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.springcloud.eurekaribbon.service.HelloService;
@RestController
public class HelloControler {
@Autowired
HelloService helloService;
@RequestMapping(value = "/hi")
public String hi(@RequestParam String name){
return helloService.hiService(name);
}
}
在瀏覽器上多次訪問http://localhost:8764/hi?name=Eureka,瀏覽器交替顯示:
hi Eureka,i am from port:8762
hi Eureka,i am from port:8763
這說明當我們通過調用restTemplate.getForObject(“http://eurekaclient/hi?name=“+name,String.class)方法時,已經做了負載均衡,訪問了不同的端口的服務實例。