[JAVA] Sie verwenden den Kontext, um MDC mit Spring WebFlux zu verwenden

Inkompatibilität zwischen WebFlux und MDC

Spring Web MVC, das häufig in Spring verwendet wird, tritt dieses Problem nicht auf.

Der Hauptunterschied zwischen WebFlux und WebMVC besteht in der Behandlung von Threads bei der Verarbeitung von Anforderungen und Antworten. Event Loop Thread, das in WebFlux verwendet wird, unterscheidet sich von Spring MVC darin, dass eine Anforderung von mehreren Threads verarbeitet wird.

Die Implementierung von MDC hängt jedoch von LocalThread ab. Mit anderen Worten, der Thread, der den MDC ausgeführt hat, verfügt über die MDC-Informationen, aber der Thread, der nicht über die MDC-Informationen verfügt, ist nicht vorhanden und wird nicht im Protokoll angezeigt.

Ich habe dieses Ereignis in der letzten Minute der ** Produktionsveröffentlichung ** durchlaufen, und hier sind die Ergebnisse dieser Untersuchung.

Pionier

In den beiden obigen Abschnitten wird beschrieben, wie MDC mit WebFlux zwischen mehreren Anwendungen weitergegeben wird. Dies ist ein Schritt weiter als dieses Thema. Ich möchte dies in Separater Artikel untersuchen.

Hauptthema

Die Antwort finden Sie im nächsten Artikel

Es gibt eine Funktion namens Kontext und drei Methoden, "logOnNext", "logOnError" und "put". Der Kontext hier ist übrigens der Kontext von Reactor. Weitere Informationen finden Sie in this, das in Reactor als Dokument beschrieben ist.

Einfach ausgedrückt ist der Kontext ein Mechanismus, mit dem "** Daten in einer reaktiven Umgebung verbreiten kann **", mit dem MDC ordnungsgemäß funktioniert. (Es scheint, dass der Mechanismus zur Weitergabe von Abonnements an der Weitergabe von Daten beteiligt ist, und ich verstehe ihn bis zu diesem Punkt nicht, aber das obige Dokument 9.8.2 enthält eine ähnliche Erklärung!)

Da es als Artikel nicht sehr wertvoll ist, werde ich mich mit jeder Methode befassen.

Was machst du grob?

--LogHelper.java definiertpublic static final String CONTEXT_MAP = "context-map";. --logOnNext und logOnError beziehen sich auf den Kontext durch den Schlüsselwert der Konstante CONTEXT_MAP. Da der Kontext eine I / F-ähnliche Karte hat, nimmt er den Wert auf. Es schiebt es in den MDC, gibt ein Protokoll aus und löscht den MDC, wenn der Betrieb beendet ist. --put schreibt mit der Konstante CONTEXT_MAP in den Kontext.

logOnNext (MDC gibt im Normalfall ein gültiges Protokoll aus)

LogHelper.java


  public static <T> Consumer<Signal<T>> logOnNext(
    Consumer<T> log) {
    return signal -> {
      if (signal.getType() != SignalType.ON_NEXT) return;
      Optional<Map<String, String>> maybeContextMap
        = signal.getContext().getOrEmpty(CONTEXT_MAP);
      if (maybeContextMap.isEmpty()) {
        log.accept(signal.get());
      } else {
        MDC.setContextMap(maybeContextMap.get());
        try {
          log.accept(signal.get());
        } finally {
          MDC.clear();
        }
      }
    };

logOnNext wird in Kombination mit der doOnEach-Methode von WebFlux verwendet. signal.getType ()! = SignalType.ON_NEXT ist ein Miso, und diese Methode reagiert nicht, wenn ein abnormales System aufgerufen wird. Es wird gezündet und protokolliert, wenn sich die Daten normal verbreiten.

logOnError (MDC gibt ein gültiges Protokoll aus, wenn es abnormal ist)

LogHelper.java


  public static <T> Consumer<Signal<T>> logOnError(
    Consumer<Throwable> log) {
    return signal -> {
      if (!signal.isOnError()) return;
      Optional<Map<String, String>> maybeContextMap
        = signal.getContext().getOrEmpty(CONTEXT_MAP);
      if (maybeContextMap.isEmpty()) {
        log.accept(signal.getThrowable());
      } else {
        MDC.setContextMap(maybeContextMap.get());
        try {
          log.accept(signal.getThrowable());
        } finally {
          MDC.clear();
        }
      }
    };
  }

Der Umriss von "logOnError" unterscheidet sich nicht wesentlich von dem von "logOnNext". Das zu referenzierende Signal hat sich jedoch geändert und protokolliert als Reaktion auf das Fehlersignal. Mit anderen Worten, wenn Sie am Ende einer Methode logOnXXX verwenden, wird Error nicht aufgerufen, wenn es normal endet, und Next wird nicht aufgerufen, wenn es abnormal endet.

put (MDC in Kontext schreiben)

LogHelper.java


  public static Function<Context, Context> put(String key, String value) {
    return ctx -> {
      Optional<Map<String, String>> maybeContextMap =
        ctx.getOrEmpty(CONTEXT_MAP);
      if (maybeContextMap.isPresent()) {
        maybeContextMap.get().put(key, value);
        return ctx;
      } else {
        Map<String, String> ctxMap = new HashMap<>();
        ctxMap.put(key, value);
        return ctx.put(CONTEXT_MAP, ctxMap);
      }
    };

Die Rolle von "put" ist unkompliziert, es werden nur die Daten im Kontext gespeichert. Die Verwendungsmethode ist wie folgt.

.subscriberContext(put("hogehogeId", response.getHogehogeId().toString()))

subscriberContext ist eine Reihe von Prozessen, soweit das Dokument angezeigt wird. Es scheint den Kontext in zu erzeugen. put nimmt auf und fügt die Konstante "CONTEXT" hinzu und gibt einen neuen Kontext zurück, sodass Sie innerhalb der Kette der Datenausbreitung endlos Werte in den MDC eintauchen können.

Ende

Ist es überhaupt unmöglich, MDC in einer reaktiven Umgebung einzusetzen? Bitte lassen Sie mich wissen, ob es einen guten Weg gibt.

Recommended Posts

Sie verwenden den Kontext, um MDC mit Spring WebFlux zu verwenden
Verwendung von MyBatis2 (iBatis) mit Spring Boot 1.4 (Spring 4)
Verwendung des eingebauten h2db mit Federstiefel
Wenn Sie Mockito mit Kotlin verwenden möchten, verwenden Sie Mockito-Kotlin
Verwenden Sie Spring JDBC mit Spring Boot
Sie müssen winpty mit Docker Exec [Windows] verwenden.
Wie man Lombok im Frühling benutzt
Verwenden Sie die Standardauthentifizierung mit Spring Boot
Hinweise zur Verwendung von Spring Data JDBC
Wie man mssql-tools mit alpine benutzt
Verwendung von ModelMapper (Spring Boot)
Beginnend mit Spring Boot 0. Verwenden Sie Spring CLI
Es scheint, dass MDC zwischen Anwendungen weitergegeben werden kann, indem der Kontext zusammen mit Spring WebFlux verwendet wird.
Wenn Sie es wagen, Integer mit "==" zu vergleichen ...
Verwendung von BootStrap mit Play Framework
Ich möchte DBViewer mit Eclipse 2018-12 verwenden! !!
Verwenden Sie Spring Security JSP-Tags mit FreeMarker
Verwenden Sie den Cache mit EhCashe 2.x mit Spring Boot
[Java] Warum verwenden Sie die Benutzeroberfläche (Spring ist ebenfalls verfügbar)?
[Spring Boot] Wenn Sie Spring Boot verwenden, war es praktisch, viele Dienstprogramme zu verwenden.
Mit Tomcat können Sie Platzhalter ($ {...}) in web.xml verwenden.
Verwendung des Java-Frameworks mit AWS Lambda! ??
Verwendung von Spring Boot-Sitzungsattributen (@SessionAttributes)
Ich möchte Java8 für jeden mit Index verwenden
Versuchen Sie, die Anmeldefunktion mit Spring Boot zu implementieren
Wenn Sie die Methode außerhalb verwenden möchten
Verwendung der Java-API mit Lambda-Ausdrücken
Super einfache Möglichkeit, Enum mit JSP zu verwenden
Verwendung des NFS-Protokolls Version 2 mit Ubuntu 18.04
[JAVA] [Spring] [MyBatis] Verwenden Sie IN () mit SQL Builder
Versuchen Sie, die Migration mit Spring Boot Flyway zu automatisieren
[Java] Artikel zum Hinzufügen einer Validierung mit Spring Boot 2.3.1.
Ich wollte Spring Boot in einem Multiprojekt gradle
Versuchen Sie, Hallo Welt mit Frühling + Gradle anzuzeigen
Was verwenden Sie beim Konvertieren in String?
[Einführung in Spring Boot] Authentifizierungsfunktion mit Spring Security
Wenn Sie SQLite mit VSCode verwenden, verwenden Sie die Erweiterung (wie die Binärdatei von sqlite3 angezeigt wird)
Eine kurze Hand, die einen JSON-Body aus ServerHttpRequest mit einem selbst erstellten WebFilter usw. mit Spring WebFlux liest
Code, der verwendet werden soll, wenn Sie Json nur mit Standardbibliotheken in Java verarbeiten möchten
Einstellungen für die Verbindung zu MySQL mit Spring Boot + Spring JDBC
Ich habe versucht, das Hochladen von Dateien mit Spring MVC zu implementieren
Ordnen Sie DTO automatisch Entitäten mit der Spring Boot-API zu
Wenn Sie die Spring Boot + Thymeleaf-Verarbeitung trennen möchten
Verwendung von Struts2 * Spring Framework (Spring Plugin) Version Juni 2017
[Java] So lassen Sie die Federkonstruktorinjektion mit Lombok weg
Verwendung von Oracle JDK 9 EA mit Travis CI
Berücksichtigung des in SpringToolSuite (STS) verwendeten Eigenschaftseditors
Verwendung der Z3-Bibliothek in Scala mit Eclipse
Ich habe versucht, mit Spring Data JPA zu beginnen
Verwendung von CommandLineRunner im Spring Batch von Spring Boot
Bis Sie mit der Entwicklung mit Spring Boot in Eclipse 1 beginnen
Verwendung der JDD-Bibliothek in Scala mit Eclipse
Booten nach Umgebung mit Spring Boot of Maven
Bis Sie mit der Entwicklung mit Spring Boot in Eclipse 2 beginnen
Verwendung des In-Memory-Job-Repositorys mit Spring Batch
Versuch, SSR Vue.js mit Spring Boot und GraalJS zu verwenden
Versuchen Sie, mit Keycloak mit Spring Security SAML (Spring 5) zu arbeiten.