服务注册与发现 | 上手实践Spring Cloud Eureka 和 Feign(三)

7,443 阅读4分钟

这是我参与11月更文挑战的第10天,活动详情查看:2021最后一次更文挑战

承接上一篇文章《上手实践Spring Cloud Eureka 和 Feign(二)》,上篇文章成功启动了注册中心,服务提供方,这篇文章基于Feign发现并消费服务。

三、Feign

这一章节我们从三个方面递进的讲Feign,第一如果没有Feign,我们将如何调用注册中心的服务;第二Feign是什么,能为我们带来哪些便利?第三,如何上手使用Feign。

3.1 如果没有Feign

为什么是Feign呢,如果不使用Feign我们该如何调用注册到Eureka上的服务呢?

如果不使用Feign,为了保证正常的服务发现和调用,我们必须要做到以下核心几步:

  • 第一步,使用Ribbon进行负载均衡
  • 第二步,获取服务的实例,并且获取根URL,再拼凑方法的URL
  • 第三步,最后使用 REST 模板或者其它方式来使用指定的服务

对于第一步,使用Ribbon获取服务实例,大致的代码如下。

 @Autowired
 private LoadBalancerClient loadBalancer; 
 
 pulic void method(){
    ServiceInstance serviceInstance=loadBalancer.choose("producer"); 
 }

对于第二步,大致的代码如下:

 pulic void method(){
    String baseUrl=serviceInstance.getUri().toString();	
    baseUrl=baseUrl+"/targetURL";
 }

最后对于第三步,执行访问,并获取结果,大致的代码如下。

pulic void method(){
    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<String> response=null;
    try{
        response=restTemplate.exchange(baseUrl,
                    HttpMethod.GET, getHeaders(),String.class);
    }catch (Exception ex)
    {
            System.out.println(ex);
    }
    System.out.println(response.getBody());
}

在整个调用过程中,是很复杂的,我们还需要处理一些空异常等等,我们使用Feign可以做到简化以上的步骤。

image.png

3.2 Feign介绍

Feign旨在简化HTTP API客户端,它是一个声明式Web Service客户端。Fegin是一个java调用HTTP的客户端binder,其灵感来自于Retrofit、JAXRS-2.0和WebSocket。

使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解,并且Feign也支持可拔插式的编码器和解码器。

那么Feign是如何工作的呢?简单地说,Feign基于将注解转换成请求模板的方式工作,参数会简单直接的应用到模板上。具体原理不做过深的阐述。

像上面提供的未使用Feign的例子,使用Feign后其调用链图如下。

image.png

正如Eureka,Spring Cloud也提供了方便使用的OpenFeign Starter,我们将看到如何使用 Netflix Feign 使服务发现和调用变得更加容易和整洁。

3.3 上手实践

在这里,我们就使用上篇文章介绍提供的服务注册中心,和服务提供方。
首先新建一个模块,引入相关依赖。

<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>

注意,我们因为要去发现Eureka的提供的服务,所以还是要引入Eureka Client的依赖。
接下来提供与服务方调用一模一样的接口GreetingClient

@FeignClient("spring-cloud-eureka-client")
public interface GreetingClient {
    
    @GetMapping("/greeting")
    String greeting();
}

所以这里就有一个问题,服务提供方和消费要声明同样一套接口,按照最佳工程实践,建议把这部分接口抽象出来作为单独Modeling,然后对应的服务提供方和消费方引入这个包。

接下来是,写启动类和Web服务,为了方便,把两者都写到启动类Launcher吧。

@SpringBootApplication
@EnableFeignClients
@RestController
public class Launcher {

    @Autowired
    private GreetingClient greetingClient;

    public static void main(String[] args) {
        SpringApplication.run(Launcher.class,args);
    }

    @GetMapping("/get-greeting")
    public String greeting(){
        return greetingClient.greeting();
    }
}

application.yml配置信息如下。

spring:
  application:
    name: spring-cloud-eureka-feign-client
server:
  port: 8080
eureka:
  client:
    serviceUrl:
      defaultZone: ${EUREKA_URI:http://localhost:8761/eureka}

然后启动这个消费服务,观察Eureka的管理页面,可以看到这个消费方也注册到Eureka注册中心了。

screenshot-127-0-0-1-8761-1636963294276.png

然后访问http://{yourhost}:8080/get-greeting,即得到hello...的回复,代表调用链通畅。

在这个例子中,并没有引入负载均衡,如果想要做到,引入Ribbon的依赖后,在代码调用服务的地方,正常去调用远程服务即可。

    @Autowired
    private RemoteCallService loadBalancer;
    
    #服务方法中这样使用去调用远程方法去获取数据
    data tmp = loadBalancer.getData(); 

四、总结

相较而言,这一整篇文章还是比较简单,上手实践一点都不难,因为整个系列都是以入门教程为主,让读者认识到这些分布式组件为什么要提供,我们能用它们分别做什么。服务注册中心还有很多,比如Zuul、ZK等等,接下来的教程会一一讲到,敬请期待!


少年,没看够?点击石头的主页,随便点点看看,说不定有惊喜呢?欢迎支持点赞/关注/评论,有你们的支持是我更文最大的动力,多谢啦!