本节示例代码在: 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进行服务调用的示例项目已完成。
参考资料