上一篇文章总结了在分布式服务系统中,服务是如何在服务中心注册与发现的,这篇文章主要总结一下注册的服务之间是怎么调用的。传统的一个项目当中,通常会有系统管理、用户管理、角色管理、人员管理等等这些模块,在分布式的系统当中,以往的同一个项目里的每一个功能模块可以相应独立拆分成一个项目也就是一个服务,然后这些服务在服务中心注册,服务与服务之间不直接调用,而通过服务中心来调用。
Spring cloud 服务间调用一般有两种方式,第一种:ribbon+restTemplate第二种:fegin
第一种ribbon+restTemplate:
Ribbon是一个负载均衡客户端,可以很好的控制http和tcp的一些行为。Feign默认集成了ribbon。
新建一个maven项目:zhangsanService,作为服务消费者,去调用上一篇文章注册到服务中心的helloService.
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.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gaox.zhangsanService</groupId>
<artifactId>zhangsanService</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>zhangsanService</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.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>Edgware.SR2</spring-cloud.version>
</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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</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>
Application.properties:
server.port=8764 spring.application.name=zhangsanService eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
ZhangsanServiceApplication.java
package com.gaox.zhangsanService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.context.annotation.Bean; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EnableEurekaClient @RestController public class ZhangsanServiceApplication { public static void main(String[] args) { SpringApplication.run(ZhangsanServiceApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } @Autowired private RestTemplate restTemplate; @RequestMapping("/hello") public String hello(String name){ String result=restTemplate.getForObject("http://HELLOSERVICE/hello?name="+name,String.class); return result; } }
依次启动serviceCenter,helloService:8762,helloService:8763,zhangsanService,在浏览器上多次访问http://localhost:8764/hello?name=zhangsan,浏览器交替显示:
你好,zhangsan。我是helloService,端口是8762
你好,zhangsan。我是helloService,端口是8763
这说明当我通地调用restTemplate.getForObject(http://HELLOSERVICE/hello?name=+zhangsan,String.class)方法时,已经作了负载均衡,访问了不同端口的服务实例。
这时项目的架构就是
一个服务注册中心:serviceCenter,端口8761
在服务注册中心注册的两个helloService实例,端口分别是8762和8763
在服务注册中心注册的另一个实例:zhangsanService,端口8764
当zhangsanService通过restTemplate调用helloService的hello接口时,因为用ribbon进行了负载均衡,所以才会出现轮流的调用8762和8763两个端口的helloService实例。
第二种方法feign:
新建一个lisiService,通过feign的方法去调用上一篇文章在服务注册中心注册的helloService。
Feign是一个声明式的伪http客户端,它使得写http客户端变得更简单,使用fegin,只需要创建一个接口,并注解,它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。
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"> <modelVersion>4.0.0</modelVersion> <groupId>com.gaox.lisiService</groupId> <artifactId>lisiService</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>lisiService</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.10.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>Edgware.SR2</spring-cloud.version> </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-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</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> </project>
Application.properties
server.port=8765 spring.application.name=lisiService eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
LisiServiceApplication.java
package com.gaox.lisiService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @EnableEurekaClient @EnableFeignClients @RestController public class LisiServiceApplication { public static void main(String[] args) { SpringApplication.run(LisiServiceApplication.class, args); } @FeignClient("helloService") public interface HelloService { @RequestMapping(value = "/hello", method = RequestMethod.GET) public String hello(@RequestParam("name") String name); } @Autowired private HelloService helloService; @RequestMapping("/hello") public String hello(@RequestParam("name")String name){ return helloService.hello(name); } }
依次启动serviceCenter,helloService:8762,helloService:8763,lisiService,多次访问http://localhost:8765/hello?name=lisi,浏览器会交替显示
你好,lisi。我是helloService,端口是8762
你好,lisi。我是helloService,端口是8763
这说明feign确实默认集成了ribbon,实现了负载均衡。