Вызов декларативного сервиса Spring Cloud Feign

задняя часть Spring MVC maven

В практике микросервисов Spring Cloud Ribbon и Spring Cloud Hystrix часто используются вместе.

Spring Cloud Feign — это высокоуровневая инкапсуляция этих двух базовых инструментов, которая расширяет поддержку аннотаций для Spring MVC на основе Netflix Feign и предоставляет декларативный метод определения клиента веб-сервиса.

Быстрый старт

Запустите реестр служб eureka-server и hello-service поставщика услуг и создайте проект весенней загрузки feign-consumer.

1. Добавьте зависимости

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

2. Аннотация позволяет притворяться

package com.ulyssesss.feignconsumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeignConsumerApplication {

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

3. Определите интерфейс HelloService

package com.ulyssesss.feignconsumer.service;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient("hello-service")
public interface HelloService {

    @GetMapping("hello")
    String hello(@RequestParam("p1") String p1, @RequestParam("p2") String p2);
}

Среди них @FeignClient указывает имя службы, а аннотация Spring MVC связывает конкретный интерфейс REST и параметры запроса.

Обратите внимание, что при определении привязки параметра нельзя опускать значение аннотаций, таких как @RequestParam и @RequestHeader. Spring MVC будет использовать имя параметра в качестве значения по умолчанию, но оно должно быть указано значением в Feign.

4. Написать контроллер

package com.ulyssesss.feignconsumer.web;

import com.ulyssesss.feignconsumer.service.HelloService;
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 FeignConsumerController {

    @Autowired
    HelloService helloService;

    @GetMapping("hello")
    public String hello(@RequestParam String p1, @RequestParam String p2) {
        System.out.println("feign consumer get hello");
        return helloService.hello(p1, p2);
    }
}

5. Настройте адрес реестра службы

spring.application.name=feign-consumer
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

Запустите все приложения, посетите http://localhost:8080/hello?p1=a&p2=b , feign-consumer обращается к hello-service с помощью декларативного вызова службы и возвращаетhello, a, b.

Унаследованные свойства

При использовании аннотаций Spring MVC для привязки интерфейсов службы их можно почти полностью скопировать из контроллера поставщика услуг, поэтому он может использовать функцию наследования Feign для дальнейшего абстрагирования, повторного использования определений интерфейса REST и сокращения объема кодирования.

1. Добавьте зависимости

Создайте проект Maven hello-service-api.Поскольку требуются аннотации Spring MVC, добавьте зависимости spring-boot-starter-web.

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

2. Определите интерфейс и DTO

Определите повторно используемые определения DTO и интерфейса в hello-service-api.

package com.ulyssesss.helloserviceapi.service;

import com.ulyssesss.helloserviceapi.dto.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

public interface HelloService {

    @GetMapping("hello")
    String hello(@RequestParam("p1") String p1, @RequestParam("p2") String p2);

    @GetMapping("user")
    User user();

    @PostMapping("post")
    String post();
}
package com.ulyssesss.helloserviceapi.dto;

public class User {
    
    private String name;
    private int age;

    public User() {}

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
    // set get
}

3. Переписать привет-сервис

Внесите зависимость hello-service-api в hello-service и перепишите HelloController.

package com.ulyssesss.helloservice.web;

import com.ulyssesss.helloserviceapi.dto.User;
import com.ulyssesss.helloserviceapi.service.HelloService;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController implements HelloService {

    @Override
    public String hello(@RequestParam String p1, @RequestParam String p2) {
        System.out.println("hello service get hello");
        return "hello, " + p1 + ", " + p2;
    }

    @Override
    public User user() {
        System.out.println("hello service get user");
        return new User("Jack", 22);
    }

    @Override
    public String post() {
        System.out.println("hello service post");
        return "post";
    }
}

4. Переписать симуляцию потребителя

Введите зависимость hello-service-api в feign-consumer и создайте RefactorHelloService для наследования от HelloService.

package com.ulyssesss.feignconsumer.service;

import com.ulyssesss.helloserviceapi.service.HelloService;
import org.springframework.cloud.netflix.feign.FeignClient;

@FeignClient(name = "hello-service")
public interface RefactorHelloService extends HelloService {
}

Измените FeignConsumerController и внедрите RefactorHelloService.

package com.ulyssesss.feignconsumer.web;

import com.ulyssesss.feignconsumer.service.RefactorHelloService;
import com.ulyssesss.helloserviceapi.dto.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FeignConsumerController {

    @Autowired
    RefactorHelloService refactorHelloService;

    @GetMapping("hello")
    public String hello(@RequestParam String p1, @RequestParam String p2) {
        System.out.println("feign consumer get hello");
        return refactorHelloService.hello(p1, p2);
    }

    @GetMapping("user")
    public User user() {
        System.out.println("feign consumer get user");
        return refactorHelloService.user();
    }

    @PostMapping("post")
    public String post() {
        System.out.println("feign consumer post");
        return refactorHelloService.post();
    }
}

Запустите все приложения, посетите http://localhost:8080/hello?p1=a&p2=b , feign-consumer обращается к hello-service с помощью декларативного вызова службы и возвращаетhello, a, b.

Используя функцию наследования Spring Cloud Feign, интерфейс может быть застеклен из контроллера, а определение интерфейса может быть передано в частный репозиторий Maven, что уменьшает конфигурацию привязки потребителя службы.

Конфигурация ленты и Hystrix

Балансировка нагрузки Spring Cloud Feign на стороне клиента реализуется через Spring Cloud Ribbon, а параметры вызова клиента можно определить, настроив ленту. Riibon и Hystrix настроены следующим образом:

spring.application.name=feign-consumer
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/

## 启用 hystrix
feign.hystrix.enabled=true
## 全局超时熔断时间
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=10000

## 全局连接超时时间
ribbon.ConnectTimeout=250
## 全局接口调用超时时间
ribbon.ReadTimeout=10000
## 全局重试所有请求(POST 请求等)开关
ribbon.OkToRetryOnAllOperations=false

## 针对 hello-service 服务,重试切换的实例数
hello-service.ribbon.MaxAutoRetriesNextServer=1
## 针对 hello-service 服务,对当前实例重试次数
hello-service.ribbon.MaxAutoRetries=0

понижение уровня обслуживания

Деградация службы, предоставляемая Hystrix, является важным методом отказоустойчивости.Поскольку Feign инкапсулирует определение HystrixCommand при определении клиента службы, невозможно использовать резервный параметр @HystrixCommand для указания логики деградации.

Spring Cloud Feign предоставляет простой способ определения перехода на более раннюю версию службы: создайте HelloServiceFallback для реализации интерфейса HelloService, объявите его как bean-компонент через @Component, реализуйте конкретную логику понижения версии в HelloServiceFallback и, наконец, объявите логику понижения версии в @FeignClient с помощью атрибута резервной копии. , Фасоль.

package com.ulyssesss.feignconsumer.service;

import com.ulyssesss.helloserviceapi.dto.User;
import org.springframework.stereotype.Component;

@Component
public class HelloServiceFallback implements RefactorHelloService {

    @Override
    public String hello(String p1, String p2) {
        return "error";
    }

    @Override
    public User user() {
        return new User("error", 0);
    }

    @Override
    public String post() {
        return "error";
    }
}
package com.ulyssesss.feignconsumer.service;

import com.ulyssesss.helloserviceapi.service.HelloService;
import org.springframework.cloud.netflix.feign.FeignClient;

@FeignClient(name = "hello-service", fallback = HelloServiceFallback.class)
public interface RefactorHelloService extends HelloService {
}

После запуска службы отключите службу hello-service поставщика услуг и получите доступ к интерфейсу feign-consumer.

исходный адрес

образец кодаДобро пожаловать в Звезду