Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

Spring WebFlux и MDC

Дата публикации: 23-02-2026 15:40:41

При использовании MDC в Spring Web MVC никаких проблем не возникает. MDC хранит информацию с привязкой к потоку. В Spring Web MVC каждый запрос обрабатывается отдельным персональным потоком. Разумеется, сервисы приложений используют пул потоков. Но для каждого запроса выделяется в полное пользование поток из этого пула до окончания обработки этого запроса. Общая схема изображена на … Читать далее Spring WebFlux и MDC

Основное содержимое страницы с новостью.

При использовании MDC1 в Spring Web MVC2 никаких проблем не возникает. MDC хранит информацию с привязкой к потоку. В Spring Web MVC каждый запрос обрабатывается отдельным персональным потоком. Разумеется, сервисы приложений используют пул потоков. Но для каждого запроса выделяется в полное пользование поток из этого пула до окончания обработки этого запроса. Общая схема изображена на рисунке ниже.

Обработка запросов в Spring Web MVC с использованием MDCОбработка запросов потоками в Spring Web MVC с использованием MDC.

В случае использования Spring WebFlux3 один запрос может обрабатываться несколькими потоками с переключением между ними. По этой причине использовать MDC напрямую в Spring WebFlux нельзя.

Обработка запросов в Spring WebFluxОбработка запросов потоками в Spring WebFlux.

К счастью, существует библиотека Micrometer context-propagation, которая позволяет сохранять значения MDC в Context реактивной цепочки и восстанавливать их оттуда.

Ладно, перейдём к делу.

Для начала нужно подключить зависимость:

<dependency>

    <groupId>io.micrometer</groupId>

    <artifactId>context-propagation</artifactId>

</dependency>

Версия зависимости прописана в spring-boot-starter-parent, здесь её указывать не нужно.

Затем необходимо зарегистрировать ThreadLocalAccessor, который будет заниматься копированием значений из MDC в контекст реактивной цепочки и обратно. После чего выполнить Hooks.enableAutomaticContextPropagation();

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

package ru.urvanov.javaexamples.springwebfluxmdc;

import java.util.List;

import org.slf4j.MDC;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.context.annotation.Configuration;

import io.micrometer.context.ContextRegistry;

import reactor.core.publisher.Hooks;

/**

* Основная настройка библиотека context-propagation.

*

* @author Fedor Urvanov (https://urvanov.ru)

*/

@Configuration

public class MdcContextPropagationConfiguration {

    /**

     * <p>

     * В этом варианте между MDC и Context реактивных потоков передаются только

     * поля, перечисленные в настройке.

     * </p>

     *

     * <p>

     * При желании можно передавать все поля

     * из MDC, для этого необходимо использовать следующий подход:

     * </p>

     * <pre>

     * {@code

     * ContextRegistry.getInstance()

     *         .registerThreadLocalAccessor(

     *                 "MDC",

     *                 MDC::getCopyOfContextMap,

     *                 MDC::setContextMap,

     *                 MDC::clear);

     * }

     * </pre>

     * @param propagationFields Список полей MDC, которые нужно передать

     * в Context реактивных потоков.

     */

    public MdcContextPropagationConfiguration(

            @Value("${spring-webflux-mdc.propagation.fields:correlationId}")

            List<String> propagationFields) {

        propagationFields.forEach(claim -> ContextRegistry.getInstance()

                .registerThreadLocalAccessor(claim, () -> MDC.get(claim),

                        value -> MDC.put(claim, value),

                        () -> MDC.remove(claim)));

        Hooks.enableAutomaticContextPropagation();

    }

}

Код выше использует настройку spring-webflux-mdc.propagation.fields. При желании вы можете перечислить в файле “application.properties” поля, которые будут перекладываться из MDC в Context реактивной цепочки и обратно:

spring-webflux-mdc.propagation.fields=correlationId,traceId,txId

По умолчанию используется только поле correlationId, так как именно оно указано в аннотации @Value.

Как указано в JavaDoc к конструктору MdcContextPropagationConfiguration, если не хочется заморачиваться с описанием полей, которые передаются из MDC и в контекст реактивной цепочки и обратно, то код в теле конструктора необходимо заменить на примерно такой:

propagationFields.forEach(ContextRegistry.getInstance()

        .registerThreadLocalAccessor(

                "MDC",

                MDC::getCopyOfContextMap,

                MDC::setContextMap,

                MDC::clear));

Hooks.enableAutomaticContextPropagation();

MDC необходимо заполнять значениями в начале обработки запроса. Значение correlationId обычно берётся из HTTP-заголовка X-Correlation-Id.

Пример фильтра, который получает correlationId из запроса и сохраняет его в MDC с последующей очисткой по окончании обработки:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

package ru.urvanov.javaexamples.springwebfluxmdc;

import java.util.UUID;

import org.slf4j.MDC;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import org.springframework.stereotype.Component;

import org.springframework.web.server.ServerWebExchange;

import org.springframework.web.server.WebFilter;

import org.springframework.web.server.WebFilterChain;

import reactor.core.publisher.Mono;

/**

* Фильтр, перекладывающий X-Correlation-Id из заголовка запроса в MDC и в

* заголовок ответа сервера.

*

* @author Fedor Urvanov (https://urvanov.ru)

*/

@Component

@Order(Ordered.HIGHEST_PRECEDENCE)

public class CorrelationIdWebFilter implements WebFilter {

    private static final String HEADER_NAME = "X-Correlation-Id";

    private static final String CORRELATION_ID_KEY = "correlationId";

    @Override

    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {

        final String correlationId;

        final String correlationIdFromHeader = exchange.getRequest()

                .getHeaders().getFirst(HEADER_NAME);

        if ((correlationIdFromHeader != null

                && (!correlationIdFromHeader.trim().isEmpty()))) {

            correlationId = correlationIdFromHeader;

        } else {

            correlationId = UUID.randomUUID().toString();

        }

        return chain.filter(exchange).doOnSubscribe(unused -> {

            exchange.getResponse().getHeaders().add(HEADER_NAME, correlationId);

            MDC.put(CORRELATION_ID_KEY, correlationId);

        }).doFinally(signalType -> {

            MDC.remove(CORRELATION_ID_KEY);

        });

    }

}

На этом настройка завершена. Любое сообщение лога будет содержать в MDC значение correlationId. Библиотеки логирования увидят их так же, как увидели бы их без реактивных потоков. Если нужно вывести это значение в консоли, то в файле “application.properties” необходимо изменить шаблон сообщения лога в консоли:

logging.pattern.console=[%-5level] [%X{correlationId}] - %m%n

Исходные коды примера на GitHub.

Вывод: использование Spring WebFlux при всех своих преимуществах приводит к дополнительным сложностям, которые приходится решать и понимать их причину.

  1. Mapped Diagnostic Context ↩︎
  2. Веб-фреймворк от Spring, использующий Project Reactor с реактивными потоками. ↩︎
  3. Первоначальный веб-фреймворк Spring, построенный на Servlet API. ↩︎
Навигация по записям

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
1WMX провел крупнейшее обновление «ПроWAF»: версия 5.0 упрощает развертывание и усиливает защиту веб-приложений и API5709-07-2026
2WMX провел крупнейшее обновление «ПроWAF»: версия 5.0 упрощает развертывание и усиливает защиту веб-приложений и API5709-07-2026
3Timeout в HttpClient не работает011.8816-06-2026
4Секреты и преимущества мессенджера Макс08.0616-06-2026
5Водители смогут обжаловать штрафы за нарушение пропускного режима в Москве по видеосвязи0001-06-2020
6Власти Москвы заявили, что данные горожан в системе пропусков защищены законодательством0025-05-2020
7В МВД рассказали, как защитить данные в облачных сервисах0026-02-2025
8Более 17 тыс. москвичей участвовали в краудсорсинг-проекте по МЦД0031-01-2020
9Медведев не стал рассказывать, является ли неформальным переговорщиком с Западом0024-03-2023

Классификация: . Схожих патентов: 0. Схожих новостей: 9. Тональность: 0. Информативность: 10.42. Источник: urvanov.ru.