使用 Feign 消费服务

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qmqm011/article/details/85013104

Feign 采用了声明式 API 接口风格,将 Java HTTP 客户端绑定到它的内部,Feign 的首要目标是将 Java HTTP 客户端调用过程变得简单。

本例采用 Maven 多模块结构,其中服务注册中心、服务提供者的代码和使用 RestTemplate 和 Ribbon 消费服务类似,这里只展示服务消费者的代码。

新建一个 Maven 工程,命名为 service-consumer,作为服务消费者,其 pom 文件如下:

<?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>
    <artifactId>service-consumer</artifactId>

    <parent>
        <artifactId>spring-cloud-feign</artifactId>
        <groupId>com.wuychn</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml 文件如下:

spring:
  application:
    name: service-consumer
server:
  port: 9004
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:9001/eureka/

程序启动类如下,@EnableEurekaClient 注解用于开启 Eureka Client 的功能,@EnableFeignClients 注解用于开启 Feign Client 的功能:

package com.wuychn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class ServiceConsumerApplication {

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

}

经过以上配置,service-consumer 就具备了 Feign 的功能,下面看看如何使用 Feign Client 调用 service-provider 的 REST API 接口。

新建一个 HiFeignClient 接口,在该接口上使用 @FeignClient 注解来声明一个 Feign Client,其中 value 表示远程调用的服务名,也就是本例中的 service-provider,configuration 指定 Feign Client 的配置类,该接口中有一个 hi() 方法,这个方法通过 Feign 来调用 service-provider 的 /hi 接口:

package com.wuychn.client;

import com.wuychn.client.config.FeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(value = "service-provider", configuration = FeignConfig.class)
public interface HiFeignClient {

    // 如果不添加@RequestParam注解,会被转化为POST请求,从而报405
    @GetMapping("/hi")
    String hi(@RequestParam(value = "name") String name);
}

需要注意的是,在 hi() 方法的参数中,需要通过 @RequestParam 注解指定参数,否则即使我们使用的是 @GetMapping,Feign 也会将其转换为 POST 请求,从而引发 405 错误。

FeignConfig 是一个配置类,其代码如下:

package com.wuychn.client.config;

import feign.Retryer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import static java.util.concurrent.TimeUnit.SECONDS;

@Configuration
public class FeignConfig {

    @Bean
    public Retryer reignRetryer() {
        return new Retryer.Default(100, SECONDS.toMillis(1), 5);
    }
}

在 FeignConfig 中,配置了一个 Retryer 类型的 Bean,这样 Feign 在远程调用失败后会进行重试,重试间隔为 100 毫秒,最大重试时间为 1 秒,重试次数为 5 次。

Feign Client 的默认配置类是 FeignClientsConfiguration,其中配置了很多 Feign 相关的 Bean,包括 Retryer、FeignLoggerFactory 等,具体可以参考其源码。如果我们没有自定义这些配置,那么默认的配置将会生效。在我们的这个例子中,FeignConfig 中配置了 Retryer,它会覆盖掉 FeignClientsConfiguration 中的默认 Retryer 配置。

在 HiService 中注入 HiFeignClient,通过 HiFeignClient 去调用服务提供者的 REST API 接口:

package com.wuychn.service;

import com.wuychn.client.HiFeignClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class HiService {

    @Autowired
    private HiFeignClient hiFeignClient;

    public String hi(String name) {
        return hiFeignClient.hi(name);
    }
}

HiController 如下:

package com.wuychn.controller;

import com.wuychn.service.HiService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HiController {

    @Autowired
    private HiService hiService;

    @GetMapping("/hi")
    public String hi(@RequestParam(required = false, defaultValue = "wuychn") String name) {
        return hiService.hi(name);
    }

}

到这里,代码就写完了,项目结构如下图:

依次启动 eureka-server、service-provider 和 service-consumer,其中 service-provider 在 9002 和 9003 两个端口分别启动两个实例,然后在浏览器中多次访问 http://localhost:9004/hi,浏览器中会依次显示如下内容:

hi wuychn, I am from port:9002

hi wuychn, I am from port:9003

可见,service-consumer 使用 Feign Client 远程调用了 service-provider 服务的 /hi 接口,并且有负载均衡的能力。

猜你喜欢

转载自blog.csdn.net/qmqm011/article/details/85013104