本节示例代码在: https://github.com/laolunsi/spring-boot-stack
一、概述
在上一节中,我们利用eureka成功注册了一个client服务,那么疑问来了,我们创建微服务的最终作用还是要去调用它。在SpringCloud下,我们怎么去调用创建的微服务呢?
先看没有微服务的情况,程序A调用程序B:
而在微服务架构中,服务调用是这样的:
在本篇文章中,我们就来建立这样一个SpringCloud下的服务调用系统。
SpringCloud中常用的服务调用方式有两种:Ribbon和Feign,而Feign是基于Ribbon封装的。这一篇,我们先基于更简单易用的Feign来实现。
官网地址:https://spring.io/projects/spring-cloud-openfeign
Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations
思路:需要以下三种角色:服务注册中心、服务提供者、服务消费者。
服务注册中心基于之前的eureka构建,服务提供者添加测试接口,而服务调用者需要引入feign的依赖和配置,然后以声明式的方式来调用服务提供者的接口。
注1:这里的服务可以简单理解为Web接口的集合。
注2:本例中的服务注册中心参考上一节建立一个即可,端口号设为8100。SpringBoot使用2.0.x,SpringCloud使用Finchley.RELEASE
版本。
二、创建服务提供者
注册一个service-producer服务,端口号8101
添加如下依赖(主要就是eureka-client):
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入netlfix-eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</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>
配置文件:
server:
port: 8101
spring:
application:
name: service-provider
eureka:
client:
service-url:
defaultZone: 'http://peer1:8100/eureka'
在Application类上加上@EnableDiscoveryClient
注解,也可以使用@EnableEurekaClient
编写一个接口:
package com.example.serviceprovider;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping(value = "hello")
public class HelloAction {
@GetMapping(value = "{name}")
public String hello(@PathVariable("name") String name) {
return "hello, " + name + ", this is service provider's response.";
}
}
三、创建服务消费者
注册一个service-consumer服务,端口号8102
引入eureka-client和feign依赖:
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 引入eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 引入openfeign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</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>
配置文件:
server:
port: 8102
spring:
application:
name: service-consumer
eureka:
client:
service-url:
defaultZone: 'http://peer1:8100/eureka' # eureka服务地址
Application类添加两个注解:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class ServiceConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceConsumerApplication.class, args);
}
}
@EnableFeignClients
注解使得服务消费者开启了Feign。
下面编写一个@FeignClient
对应的接口,如下:
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
// 这里的name对应的就是要调用的服务的名称
@FeignClient(name = "service-provider")
public interface HelloRemote {
@GetMapping(value = "hello/{name}")
public String hello(@PathVariable("name") String name);
}
如上,使用了@FeignClient(name = "service-provider")
标明对应要调用的服务,name就是服务的名称。
下面的方法与服务提供者(service provider)中编写的接口名称、参数等均相同。
然后在服务消费者里编写一个新的接口,通过调用它来进一步调用服务提供者:
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;
@RestController
@RequestMapping(value = "consumer")
public class TestAction {
@Autowired
private HelloRemote helloRemote;
@GetMapping(value = "test")
public String consume(String name) {
String res = helloRemote.hello(name);
String str = "服务消费者调用服务提供者,提供参数name=" + name + ",获取返回值:" + res;
System.out.println(str);
return str;
}
}
四、启动与测试
分别启动eureka-server
, service-provider
, service-consumer
,打开浏览器,输入http://localhost:8100
,看到如下页面:
两个服务都注册成功了。
下面我们测试一下,首先测试一下service-producer提供的接口是否正常:
最后我们利用service-consumer的接口来测试服务互相调用是否正常:
至此,我们利用Eureka做服务注册与发现,Feign进行服务调用的示例项目已完成。
参考资料
- 纯洁的微笑-SpringCloud专栏3-服务提供与调用:http://www.ityouknow.com/springcloud/2017/05/12/eureka-provider-constomer.html
- 方志朋-SpringCloud系列3-服务消费者(Feign):https://blog.csdn.net/forezp/article/details/69808079