SpringCloudAlibaba OpenFeign-Integration und detaillierte Erklärung

SpringCloudAlibaba OpenFeign

Nachdem wir zuvor die Nacos-Dienstregistrierung und -Erkennung verwendet haben, kann der Dienst-Remoteaufruf mit RestTemplate+Ribbon oder OpenFeign aufgerufen werden. In der tatsächlichen Entwicklung wird RestTemplate selten zum Aufrufen von Diensten verwendet. Bei jedem Aufruf müssen Adressen eingegeben und verschiedene Parameter konfiguriert werden, was sehr mühsam ist. Dieses Problem kann mit OpenFeign gelöst werden.

Wenn es also um OpenFeign geht, müssen Sie Feign erwähnen, da OpenFeign eine erweiterte Version von Feign ist. Feign ist ein leichter Restful-HTTP-Dienstclient mit integriertem Menüband für den Client-Lastausgleich. Wenn Sie Feign verwenden, müssen Sie nur eine Schnittstelle definieren und Anmerkungen hinzufügen, was den schnittstellenorientierten Programmiergewohnheiten entspricht und Remote-Dienstaufrufe einfacher macht.

OpenFeign ist eine weitere Kapselung von Feign, wodurch es die Standardanmerkungen und HttpMessageConverter von Spring MVC wie @RequestMapping unterstützt.

Integrieren Sie OpenFeign

Integrieren Sie OpenFeign in den Consumer-Client

导入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

bootstrap.ymlFügen Sie OpenFeign-Unterstützung für Sentinel hinzu und fügen Sie Konfigurationselemente feign.sentinel.enabledhinzu

server:
  port: 9001
spring:
  application:
    name: consumer # 应用名

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址
    sentinel:
      transport:
        port: 8719 # 启动http server,并且该服务与Sentinel仪表板进行交互,使sentinel可以控制应用,若端口占用则8719+1依次扫描
        dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:	# 增加对sentinel的支持
  sentinel:
    enabled: true

Lassen Sie mich hier darüber sprechen. Wenn keine feign.sentinel.enabled=trueKonfiguration hinzugefügt wird, wird die durch das Fallback-Attribut in @FeignClient definierte benutzerdefinierte Verarbeitungslogik wie Ausnahmen und Strombegrenzung nicht wirksam.

Fügen Sie der Hauptstartklasse eine Anmerkung hinzu @EnableFeignClientsund markieren Sie sie wie folgt, um OpenFeign zu aktivieren:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class Consumer {
    
    

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

Der Autor möchte hier noch einmal erwähnen, dass bei einem verteilten Projekt beim Extrahieren von Openfeign als separates Servicemodul der Paketname in meinem Openfeign möglicherweise nicht mit anderen Modulen übereinstimmt. Sie können die FeignClient-Komponente selbst deklarieren, um den Scanpfad festzulegen von FeignClient basePackages. Beispiele sind wie folgt:

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.alibaba.provider.feigns")
public class Consumer {
    
    

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

Fügen Sie einen FeignClient-Client hinzu

/**
 * "provider" : 表示调用的生产者服务名
 * fallback:异常时进入的处理类
 */
@FeignClient(value = "provider", fallback = OpenFeignTestServiceFallback.class)
public interface OpenFeignTestService {
    
    

    @RequestMapping(value = "/openFeignProviderTest", method = RequestMethod.GET)
    public String openFeignProviderTest();

}

Erstellen Sie OpenFeignTestServiceFallback für die Fallback-Verarbeitung

@Component
public class OpenFeignTestServiceFallback implements OpenFeignTestService{
    
    

    @Override
    public String openFeignProviderTest() {
    
    
        return "我是兜底方法";
    }
}

Erstellen Sie einen Controller als Schnittstelle zum einfachen Aufrufen

@RestController
public class OpenFeignTestController {
    
    
    
    @Resource
    private OpenFeignTestService openFeignTestService;
    
    @RequestMapping("/openFeignTest")
    public String openFeignTest() {
    
    
        return openFeignTestService.openFeignProviderTest();
    }
    
}

Stellen Sie auf der Seite des Dienstproduzenten eine Schnittstelle bereit

@RestController
public class OpenFeignProviderTest {
    
    

    @RequestMapping("/openFeignProviderTest")
    public String openFeignProviderTest() {
    
    
        return "OpenFeignTestController#openFeignProviderTest" + RandomUtils.nextInt(0, 1000);
    }

}

Testschnittstelle

/openFeignTestSie können Curl oder einen Browser verwenden, um den Schnittstellentest auf der Service-Consumer-Seite aufzurufen .

curl http://localhost:9001/openFeignTest
==>OpenFeignTestController#openFeignProviderTest748

Optimieren Sie den Code:

In der @FeignClient-Annotation füllt das Wertattribut den Dienstnamen des Dienstanbieters aus. Es ist unangemessen, den Wert direkt zu schreiben. Wenn sich der Name des Dienstanbieters ändert, muss das, was hier geschrieben wird, geändert werden, und wenn ja wird verwendet in In mehr Fällen muss es überall geändert werden. Wie man es löst?

  • Verwenden Sie eine separate Klasse für den Dienstnamen und definieren Sie statische Konstanten
  • Verwenden Sie die Konfigurationsdateimethode und verwenden Sie Ausdrücke, um sie abzurufen.

Das Definieren einer statischen Konstantenklasse wird nicht mehr demonstriert. Verwenden Sie die Konfigurationsdateimethode:

provider:
  name: provider

Verwenden Sie den Ausdruck, um den FeignClient-Client abzurufen

@FeignClient(value = "${provider.name}", fallback = OpenFeignTestServiceFallback.class)

Wird in Kombination mit Sentinel-Regeln verwendet

Unabhängig davon, ob es sich um RestTemplate+Ribbon oder den Remote-Aufruf von OpenFeign handelt, unterstützt es Sentinel. Konfigurieren Sie die Regeln zur Ressourcenflusssteuerung im Sentinel-Bedienfeld

Hinweis: Sentinel ist eine Lazy-Loading-Methode. Sie müssen die Schnittstelle einmal aufrufen, bevor Sie Regeln in der Konsole hinzufügen können

Fügen Sie im Sentinel-Panel openFeignProviderTestFlusskontrollregeln, Schwellenwerttyp QPS, eigenständiger Schwellenwert 1 hinzu

Fügen Sie hier eine Bildbeschreibung ein

/openFeignProviderTestOkay, wir haben den Datenverkehr auf der Serverseite begrenzt. Versuchen Sie daher, mehrmals hintereinander auf die Client-Schnittstelle zuzugreifen.

Fügen Sie hier eine Bildbeschreibung ein

Es ist ersichtlich, dass bei einigen Anforderungen die Fallback-Verschlechterung auftritt.

Wie also mit Ausnahmen umgehen?

Ändern Sie den Code der Serverschnittstelle, legen Sie eine Ausnahme fest und testen Sie die Schnittstelle

Fügen Sie hier eine Bildbeschreibung ein

Ok, ich habe festgestellt, dass bei einer Ausnahme auf der Serverseite immer noch der Fallback-Prozess auf der Clientseite aktiviert wird. Ist das nicht sehr schön?

Was passiert also, wenn der Server ausfällt? Versuchen Sie, den Server auszuschalten.

Fügen Sie hier eine Bildbeschreibung ein

Ja, Sie können auch in die Fallback-Verarbeitung einsteigen.

Implementieren Sie den Lastausgleich

OpenFeign verfügt außerdem über eine Lastausgleichsfunktion. Bei mehreren Servern wird der entsprechende Algorithmus verwendet, um einen Server zu finden, der Anfragen stellt.

Als nächstes gibt der Server die Portnummer des aktuellen Projekts aus und erstellt ein neues Serverprojekt.

@RestController
public class OpenFeignProviderTest {
    
    

    @Value("${server.port}")
    private Integer port;
    
    @RequestMapping("/openFeignProviderTest")
    public String openFeignProviderTest() {
    
    
        return "OpenFeignTestController#openFeignProviderTest" + port;
    }

}

Erstellen Sie ein neues Projekt und stellen Sie den Port auf 8003 ein.

server:
  port: 8002
...多余部分省略

server:
  port: 8003
...多余部分省略

Das Projekt ist gestartet und in nacos zu finden. Es gibt zwei Instanzen des Servers.

Fügen Sie hier eine Bildbeschreibung ein

Rufen Sie die Client-Schnittstelle mehrmals auf, um die Ergebnisse anzuzeigen

Fügen Sie hier eine Bildbeschreibung ein

Fordern Sie Dienste abfragend an.

OpenFeign-Timeout-Konfiguration

2020版本以前Die Standardwartezeit von OpenFeign für die Rückgabe von Daten durch die Schnittstelle beträgt 1s. Wenn sie 1 Sekunde überschreitet, wird ein Fehler gemeldet. Wenn ein Fallback vorliegt, wird eine Fallback-Verarbeitung durchgeführt.

Nach der Version 2020 lautet der Quellcode wie folgt:

public Options() {
    
    
    //10L: connectTimeout
    //60L: readTimeout
    this(10L, TimeUnit.SECONDS, 60L, TimeUnit.SECONDS, true);
}

connectTimeout beträgt 10 Sekunden, readTimeout beträgt 60 Sekunden

Mit gewöhnlichen Schnittstellen gibt es kein Problem, aber wenn es sich um ein zeitaufwändiges Geschäft handelt, muss der Ausführungsprozess länger als 1 Sekunde dauern, was nicht sinnvoll ist.

Dann bietet OpenFeign eine Timeout-Konfiguration. Timeout-Konfiguration zur Consumer- Datei bootstrap.ymlhinzufügen :

  • feign.client.config.default.connectTimeout:Timeout beim Verbindungsaufbau
  • feign.client.config.default.readTimeout: Timeout-Konfiguration der Zeit, die zum Lesen von Ressourcen vom Server benötigt wird, nachdem die Verbindung hergestellt wurde
server:
  port: 9001
spring:
  application:
    name: consumer # 应用名

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址
    sentinel:
      transport:
        port: 8719 # 启动http server,并且该服务与Sentinel仪表板进行交互,使sentinel可以控制应用,若端口占用则8719+1依次扫描
        dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:
  sentinel:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 2000 # 建立连接超时时间
        readTimeout: 2000   # 读取资源超时时间
@RequestMapping("/openFeignProviderTest")
public String openFeignProviderTest() throws InterruptedException {
    
    
    Thread.sleep(5000);
    return "OpenFeignTestController#openFeignProviderTest" + port;
}

Fügen Sie hier eine Bildbeschreibung ein

Hier schlafen wir absichtlich 5 Sekunden lang und die Zeitüberschreitungszeit beträgt 2 Sekunden. Dann muss eine Zeitüberschreitung erfolgen und der Fallback wird aktiviert.

Versuchen Sie, die Zeit länger anzupassen

..
feign:
  sentinel:
    enabled: true
  client:
    config:
      default:
        connectTimeout: 7000 # 建立连接超时时间
        readTimeout: 7000   # 读取资源超时时间

Fügen Sie hier eine Bildbeschreibung ein

Kein Problem

OpenFeigns Protokoll

Um das Auffinden von Ausnahmen im Allgemeinen in der lokalen Entwicklungsumgebung zu erleichtern, drucken Sie die Protokolldetails der OpenFeign-Remote-Aufrufschnittstelle aus.

Fügen Sie die Konfiguration der Protokollebene in der Datei hinzu und fügen Sie den Paketnamen des 服务消费者bootstrap.ymlneuen Konfigurationselements hinzu, um die Schnittstelle zu deklarieren. Die vollständige Konfiguration lautet wie folgt:logging.level.

server:
  port: 9001
spring:
  application:
    name: consumer # 应用名

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址
    sentinel:
      transport:
        port: 8719 # 启动http server,并且该服务与Sentinel仪表板进行交互,使sentinel可以控制应用,若端口占用则8719+1依次扫描
        dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:
  sentinel:
    enabled: true

  client:
    config:
      default:
        connectTimeout: 5000 # 建立连接超时时间
        readTimeout: 5000   # 读取资源超时时间

logging:
  level:
    com.alibaba.provider.feigns: debug # 打印自己项目中com.alibaba.provider.feigns包的日志,级别是debug级别

Erstellen Sie dann eine Konfigurationsklasse in Java

@Configuration
public class OpenFeignLoggerConfiguration {
    
    
    
    @Bean
    public Logger.Level openFeignLoggerLevel() {
    
    
        return Logger.Level.FULL;   // FULL日志级别
    }
    
}

OpenFeign-Protokolle haben die folgenden Ebenen

  • NONE: kein Datensatz, Standard
  • BASIC: Nur Anforderungsmethode und URL sowie Antwortstatuscode und Ausführungszeit aufzeichnen
  • HEADERS: Zeichnen Sie nur grundlegende Informationen sowie Anforderungs- und Antwortheader auf
  • VOLLSTÄNDIG: Zeichnen Sie den Header, den Text und die Metadaten der Anfrage und Antwort mit möglichst vollständigen Informationen auf

Nach der Konfiguration sieht es wie folgt aus:

Fügen Sie hier eine Bildbeschreibung ein

Die Informationen sind sehr vollständig und leicht zu beheben.

Anforderungs- und Antwortkomprimierung

OpenFeign unterstützt die Anforderungs- und Antwortkomprimierung durch einfache Konfiguration, gzipum die Effizienz der Datenübertragung zu verbessern.

Durch das Einschalten der Komprimierung können Netzwerkressourcen effektiv gespart werden, es erhöht jedoch den Druck auf die CPU während des Komprimierungs- und Dekomprimierungsprozesses. Es ist am besten, den Parameter für die minimale Anforderungslänge zu erhöhen.

bootstrap.ymlFügen Sie der Datei eine Parameterkonfiguration (Dienstkonsumentenseite) hinzu :

server:
  port: 9001
spring:
  application:
    name: consumer # 应用名

  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 # nacos服务地址
    sentinel:
      transport:
        port: 8719 # 启动http server,并且该服务与Sentinel仪表板进行交互,使sentinel可以控制应用,若端口占用则8719+1依次扫描
        dashboard: 127.0.0.1:8080 # 仪表版访问地址
feign:
  sentinel:
    enabled: true

  client:
    config:
      default:
        connectTimeout: 5000 # 建立连接超时时间
        readTimeout: 5000   # 读取资源超时时间
        
  compression:
    request:
      enabled: true # 请求压缩启用
      mime-types: text/xml, application/xml, application/json # 要压缩的类型
      min-request-size: 2048 # 最小请求长度 单位:字节
    response:
      enabled: true # 响应压缩启用
      

logging:
  level:
    com.alibaba.provider.feigns: debug # 打印com.alibaba.provider.feigns包的日志,级别是debug级别

Nach der Komprimierung können Sie die Protokollsituation sehen:

Fügen Sie hier eine Bildbeschreibung ein

Übergabe von OpenFeign-Parametern

Einfache Parameterübergabe

Serverschnittstelle

@PostMapping("/sampleParamsProviderTest")
public String sampleParamsProviderTest(@RequestParam("name") String name, @RequestParam("id") Integer id) {
    
    
    return "OpenFeignProviderTest# sampleParamsProviderTest#" + port + "id=" + id + ",name=" + name;
}

ConsumerOpenFeign

@FeignClient(value = "${provider.name}", fallback = OpenFeignTestServiceFallback.class)
public interface OpenFeignTestService {
    
    

    @PostMapping("/sampleParamsProviderTest")
    public String sampleParamsProviderTest(@RequestParam("name") String name, @RequestParam("id") Integer id);

}

Rückfall der Verbraucher

@Component
public class OpenFeignTestServiceFallback implements OpenFeignTestService {
    
    
    @Override
    public String sampleParamsProviderTest(String name, Integer id) {
    
    
        return "我是兜底方法" + name + id;
    }
}

Verbraucher stellen eine Schnittstelle zum Testen bereit

@GetMapping("/sampleParamsProviderTest")
public String sampleParamsProviderTest() {
    
    
    return openFeignTestService.sampleParamsProviderTest("gangge", 1);
}

Fügen Sie hier eine Bildbeschreibung ein

@SpringQueryMap-Objektübergabe

Erstellen Sie dann zunächst ein zu übergebendes Objekt, das von Dienstanbietern und Verbrauchern gemeinsam genutzt wird.

public class Params {
    
    
    
    private Integer id;
    private String name;

    .../getter、setter方法
}

Der Dienstanbieter erstellt eine Schnittstelle, über die Verbraucher anrufen können

@GetMapping("/springQueryMapProviderTest")
public String springQueryMapProviderTest(Params params) {
    
    
    return "OpenFeignProviderTest# sampleParamsProviderTest#" + port + "id=" + params.getId() + ",name=" + params.getName();
}

ConsumerOpenFeign

@GetMapping("/springQueryMapProviderTest")
public String springQueryMapProviderTest(@SpringQueryMap Params params);

Rückfall der Verbraucher

@Override
public String springQueryMapProviderTest(Params params) {
    
    
    return "我是兜底方法" + params.getId() + params.getName();
}

Verbraucherschnittstelle

@GetMapping("/springQueryMapTest")
public String springQueryMapTest() {
    
    
    Params params = new Params();
    params.setId(1);
    params.setName("gangge");
    return openFeignTestService.springQueryMapProviderTest(params);
}

Ergebnis

Fügen Sie hier eine Bildbeschreibung ein

Komplexe Objektübertragung

Im Falle von Objekten innerhalb von Objekten bereiten Sie ein ComplexObjectund Resultein Objekt vor (sowohl Anbieter als auch Verbraucher müssen sie erstellen).

ComplexObject

public class ComplexObject {
    
    
    private Params params;

    public Params getParams() {
    
    
        return params;
    }

    public void setParams(Params params) {
    
    
        this.params = params;
    }
}

Result

public class Result {
    
    
    private Integer code;
    private String describe;

    public Integer getCode() {
    
    
        return code;
    }

    public void setCode(Integer code) {
    
    
        this.code = code;
    }

    public String getDescribe() {
    
    
        return describe;
    }

    public void setDescribe(String describe) {
    
    
        this.describe = describe;
    }
}

Schreiben Sie eine Schnittstelle für den Dienstanbieter, akzeptieren Sie Verbraucheraufrufe und geben Sie dann das Ergebnisobjekt zurück.

@PostMapping("/complexObjectProviderTest")
public Result complexObjectProviderTest(@RequestBody ComplexObject complexObject) {
    
    
    Result result = new Result();
    result.setCode(200);
    result.setDescribe("#complexObjectProviderTest" + complexObject.getParams().getName() + complexObject.getParams().getId());
    return result;
}

Der Verbraucher deklariert die Clientschnittstelle und den Fallback-Vorgang

@PostMapping("/complexObjectProviderTest")
public Result complexObjectProviderTest(@RequestBody ComplexObject complexObject);

@Override
public Result complexObjectProviderTest(ComplexObject complexObject) {
    
    
    return null;
}

Ergebnisobjekt zurückgeben**

@PostMapping("/complexObjectProviderTest")
public Result complexObjectProviderTest(@RequestBody ComplexObject complexObject) {
    
    
    Result result = new Result();
    result.setCode(200);
    result.setDescribe("#complexObjectProviderTest" + complexObject.getParams().getName() + complexObject.getParams().getId());
    return result;
}

Der Verbraucher deklariert die Clientschnittstelle und den Fallback-Vorgang

@PostMapping("/complexObjectProviderTest")
public Result complexObjectProviderTest(@RequestBody ComplexObject complexObject);

@Override
public Result complexObjectProviderTest(ComplexObject complexObject) {
    
    
    return null;
}

Anmerkungen sind für komplexe Objekte völlig in Ordnung @RequestBody, es kann jedoch nur einen @RequestBody-Parameter geben.

Acho que você gosta

Origin blog.csdn.net/weixin_45248492/article/details/132634506
Recomendado
Clasificación