diff --git a/microservices-modules/micronaut-configuration/README.md b/microservices-modules/micronaut-configuration/README.md
new file mode 100644
index 000000000000..29425602829f
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/README.md
@@ -0,0 +1,6 @@
+## Micronaut
+
+This module contains articles about Micronaut version 4 major.
+
+### Relevant Articles:
+-
diff --git a/microservices-modules/micronaut-configuration/pom.xml b/microservices-modules/micronaut-configuration/pom.xml
new file mode 100644
index 000000000000..1dc87f6a29c8
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/pom.xml
@@ -0,0 +1,157 @@
+
+
+ 4.0.0
+ com.baeldung.micronaut
+ micronaut-configuration
+ 0.1
+ ${packaging}
+ micronaut-configuration
+
+
+ com.baeldung
+ microservices-modules
+ 1.0.0-SNAPSHOT
+
+
+
+
+ io.micronaut
+ micronaut-runtime
+ ${micronaut.version}
+
+
+ io.micronaut
+ micronaut-http-client
+ ${micronaut.version}
+
+
+ io.micronaut
+ micronaut-inject
+ ${micronaut.version}
+
+
+ io.micronaut
+ micronaut-http-server-netty
+ ${micronaut.version}
+
+
+ io.micronaut
+ micronaut-jackson-databind
+ ${micronaut.version}
+
+
+ io.micronaut.validation
+ micronaut-validation
+ ${micronaut.validation.version}
+
+
+ javax.annotation
+ javax.annotation-api
+ 1.3.2
+
+
+ org.yaml
+ snakeyaml
+ 2.2
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.34
+ provided
+ true
+
+
+
+ ch.qos.logback
+ logback-classic
+ 1.4.12
+ runtime
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ ${junit.jupiter.version}
+ test
+
+
+ org.junit
+ junit-bom
+ ${junit.jupiter.version}
+ pom
+ test
+
+
+ io.micronaut.test
+ micronaut-test-junit5
+ ${micronaut.test.version}
+ test
+
+
+ io.micronaut.test
+ micronaut-test-rest-assured
+ ${micronaut.test.version}
+ test
+
+
+ io.reactivex.rxjava3
+ rxjava
+ 3.1.6
+ compile
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ ${jdk.version}
+ ${release.version}
+
+
+ org.projectlombok
+ lombok
+ 1.18.34
+
+
+ io.micronaut
+ micronaut-inject-java
+ ${micronaut.version}
+
+
+ io.micronaut.validation
+ micronaut-validation-processor
+ ${micronaut.validation.version}
+
+
+
+ -Amicronaut.processing.group=${project.groupId}
+ -Amicronaut.processing.module=${project.artifactId}
+
+
+
+
+
+
+
+ 17
+ 17
+ UTF-8
+ 17
+ 17
+ jar
+
+ 4.4.3
+ com.baeldung.micronaut.httpfilters.ServerApplication
+ 4.6.1
+ netty
+ 4.3.0
+ 5.9.1
+
+
diff --git a/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/ServerApplication.java b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/ServerApplication.java
new file mode 100644
index 000000000000..edabcae286a8
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/ServerApplication.java
@@ -0,0 +1,10 @@
+package com.baeldung.micronaut.httpfilters;
+
+import io.micronaut.runtime.Micronaut;
+
+public class ServerApplication {
+
+ public static void main(String[] args) {
+ Micronaut.run(ServerApplication.class, args);
+ }
+}
diff --git a/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/controller/FilteredController.java b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/controller/FilteredController.java
new file mode 100644
index 000000000000..7b4e033cdaea
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/controller/FilteredController.java
@@ -0,0 +1,21 @@
+package com.baeldung.micronaut.httpfilters.controller;
+
+import io.micronaut.http.HttpResponse;
+import io.micronaut.http.annotation.Controller;
+import io.micronaut.http.annotation.Get;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller("/filters-annotations")
+public class FilteredController {
+
+ @Get("/endpoint1")
+ public HttpResponse endpoint1() {
+ return HttpResponse.ok("Endpoint 1");
+ }
+
+ @Get("/endpoint2")
+ public HttpResponse endpoint2() {
+ return HttpResponse.ok("Endpoint 2");
+ }
+}
diff --git a/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/filters/CustomFilter.java b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/filters/CustomFilter.java
new file mode 100644
index 000000000000..d84877740db5
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/filters/CustomFilter.java
@@ -0,0 +1,38 @@
+package com.baeldung.micronaut.httpfilters.filters;
+
+import static com.baeldung.micronaut.httpfilters.utils.CustomHttpHeaders.CUSTOM_HEADER_KEY;
+import static com.baeldung.micronaut.httpfilters.utils.CustomHttpHeaders.X_TRACE_HEADER_KEY;
+
+import io.micronaut.core.order.Ordered;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.MutableHttpResponse;
+import io.micronaut.http.annotation.RequestFilter;
+import io.micronaut.http.annotation.ResponseFilter;
+import io.micronaut.http.annotation.ServerFilter;
+import io.micronaut.scheduling.TaskExecutors;
+import io.micronaut.scheduling.annotation.ExecuteOn;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@ServerFilter(patterns = { "**/endpoint*" })
+public class CustomFilter implements Ordered {
+
+ @RequestFilter
+ @ExecuteOn(TaskExecutors.BLOCKING)
+ public void filterRequest(HttpRequest> request) {
+ String customRequestHeader = request.getHeaders()
+ .get(CUSTOM_HEADER_KEY);
+ log.info("request header: {}", customRequestHeader);
+ }
+
+ @ResponseFilter
+ public void filterResponse(MutableHttpResponse> res) {
+ res.getHeaders()
+ .add(X_TRACE_HEADER_KEY, "true");
+ }
+
+ @Override
+ public int getOrder() {
+ return 2;
+ }
+}
diff --git a/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/filters/PrivilegedUsersEndpointFilter.java b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/filters/PrivilegedUsersEndpointFilter.java
new file mode 100644
index 000000000000..40fe7c947e6f
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/filters/PrivilegedUsersEndpointFilter.java
@@ -0,0 +1,33 @@
+package com.baeldung.micronaut.httpfilters.filters;
+
+import static com.baeldung.micronaut.httpfilters.utils.CustomHttpHeaders.PRIVILEGED_USER_HEADER_KEY;
+
+import org.reactivestreams.Publisher;
+
+import io.micronaut.core.order.Ordered;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.MutableHttpResponse;
+import io.micronaut.http.annotation.Filter;
+import io.micronaut.http.filter.HttpServerFilter;
+import io.micronaut.http.filter.ServerFilterChain;
+import io.reactivex.rxjava3.core.Flowable;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Filter(patterns = { "**/*1" })
+public class PrivilegedUsersEndpointFilter implements HttpServerFilter, Ordered {
+
+ @Override
+ public Publisher> doFilter(HttpRequest> request, ServerFilterChain chain) {
+ log.info("Privileged user was filtered");
+
+ return Flowable.fromPublisher(chain.proceed(request))
+ .doOnNext(response -> response.getHeaders()
+ .add(PRIVILEGED_USER_HEADER_KEY, "true"));
+ }
+
+ @Override
+ public int getOrder() {
+ return 3;
+ }
+}
diff --git a/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/filters/RequestIDFilter.java b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/filters/RequestIDFilter.java
new file mode 100644
index 000000000000..519215a1f115
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/filters/RequestIDFilter.java
@@ -0,0 +1,42 @@
+package com.baeldung.micronaut.httpfilters.filters;
+
+import static com.baeldung.micronaut.httpfilters.utils.CustomHttpHeaders.REQUEST_ID_HEADER_KEY;
+
+import java.util.UUID;
+
+import io.micronaut.core.annotation.Order;
+import io.micronaut.core.order.Ordered;
+import io.micronaut.http.HttpRequest;
+import io.micronaut.http.MutableHttpResponse;
+import io.micronaut.http.annotation.RequestFilter;
+import io.micronaut.http.annotation.ServerFilter;
+import io.micronaut.http.filter.FilterContinuation;
+import io.micronaut.scheduling.TaskExecutors;
+import io.micronaut.scheduling.annotation.ExecuteOn;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@ServerFilter(patterns = { "**/endpoint*" })
+@Order(1)
+public class RequestIDFilter implements Ordered {
+
+ @RequestFilter
+ @ExecuteOn(TaskExecutors.BLOCKING)
+ public void filterRequest(HttpRequest> request, FilterContinuation> continuation) {
+ String requestIdHeader = request.getHeaders()
+ .get(REQUEST_ID_HEADER_KEY);
+ if (requestIdHeader == null || requestIdHeader.trim()
+ .isEmpty()) {
+ requestIdHeader = UUID.randomUUID()
+ .toString();
+ log.info("request ID not received. Created and will return one with value: [{}]", requestIdHeader);
+ } else {
+ log.info("request ID received. Request ID: [{}]", requestIdHeader);
+ }
+
+ MutableHttpResponse> res = continuation.proceed();
+
+ res.getHeaders()
+ .add(REQUEST_ID_HEADER_KEY, requestIdHeader);
+ }
+}
diff --git a/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/utils/CustomHttpHeaders.java b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/utils/CustomHttpHeaders.java
new file mode 100644
index 000000000000..c5fb29386660
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/main/java/com/baeldung/micronaut/httpfilters/utils/CustomHttpHeaders.java
@@ -0,0 +1,12 @@
+package com.baeldung.micronaut.httpfilters.utils;
+
+public class CustomHttpHeaders {
+
+ private CustomHttpHeaders() {
+ }
+
+ public static final String X_TRACE_HEADER_KEY = "X-Trace-Enabled";
+ public static final String REQUEST_ID_HEADER_KEY = "Request-ID";
+ public static final String CUSTOM_HEADER_KEY = "custom-header";
+ public static final String PRIVILEGED_USER_HEADER_KEY = "Privileged-User";
+}
diff --git a/microservices-modules/micronaut-configuration/src/main/resources/application.yml b/microservices-modules/micronaut-configuration/src/main/resources/application.yml
new file mode 100644
index 000000000000..f21def890862
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/main/resources/application.yml
@@ -0,0 +1,4 @@
+micronaut:
+ server:
+ port: 21000
+ context-path: /micronaut-configuration-tutorials
diff --git a/microservices-modules/micronaut-configuration/src/main/resources/logback.xml b/microservices-modules/micronaut-configuration/src/main/resources/logback.xml
new file mode 100644
index 000000000000..4781b201da04
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/main/resources/logback.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
diff --git a/microservices-modules/micronaut-configuration/src/test/java/com/baeldung/micronaut/httpfilters/FiltersOrderTest.java b/microservices-modules/micronaut-configuration/src/test/java/com/baeldung/micronaut/httpfilters/FiltersOrderTest.java
new file mode 100644
index 000000000000..44ad21772175
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/test/java/com/baeldung/micronaut/httpfilters/FiltersOrderTest.java
@@ -0,0 +1,102 @@
+package com.baeldung.micronaut.httpfilters;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.Optional;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+
+import com.baeldung.micronaut.httpfilters.filters.CustomFilter;
+import com.baeldung.micronaut.httpfilters.filters.PrivilegedUsersEndpointFilter;
+import com.baeldung.micronaut.httpfilters.filters.RequestIDFilter;
+
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.read.ListAppender;
+import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
+import io.restassured.specification.RequestSpecification;
+
+@MicronautTest
+class FiltersOrderTest {
+
+ private ListAppender customFilterLogs;
+ private ListAppender requestIDFilterLogs;
+ private ListAppender privilegedUsersEndpointFilterLogs;
+
+ @BeforeEach
+ void setUp() {
+ customFilterLogs = getListAppenderForClass(CustomFilter.class);
+ requestIDFilterLogs = getListAppenderForClass(RequestIDFilter.class);
+ privilegedUsersEndpointFilterLogs = getListAppenderForClass(PrivilegedUsersEndpointFilter.class);
+ }
+
+ @Test
+ public void givenFilterOrder_whenRequestIsFilteredByAllFilters_thenTheOrderIsRight(RequestSpecification spec) {
+ spec.given()
+ .basePath("micronaut-configuration-tutorials/filters-annotations")
+ .when()
+ .get("/endpoint1");
+
+ Optional customFilterLog = customFilterLogs.list.stream()
+ .filter(e -> e.getMessage()
+ .contains("request header:"))
+ .findFirst();
+ Optional requestIdFilterLog = requestIDFilterLogs.list.stream()
+ .filter(e -> e.getMessage()
+ .contains("request ID"))
+ .findFirst();
+ Optional privilegedUserFilterLog = privilegedUsersEndpointFilterLogs.list.stream()
+ .filter(e -> e.getMessage()
+ .contains("Privileged user was filtered"))
+ .findFirst();
+
+ assertThat(customFilterLog).isPresent();
+ assertThat(requestIdFilterLog).isPresent();
+ assertThat(privilegedUserFilterLog).isPresent();
+ assertThat(customFilterLog.get()
+ .getNanoseconds()).isGreaterThan(requestIdFilterLog.get()
+ .getNanoseconds());
+ assertThat(privilegedUserFilterLog.get()
+ .getNanoseconds()).isGreaterThan(customFilterLog.get()
+ .getNanoseconds());
+ }
+
+ @Test
+ public void givenFilterOrder_whenRequestIsFilteredBy2Filters_thenTheOrderIsRight(RequestSpecification spec) {
+ spec.given()
+ .basePath("micronaut-configuration-tutorials/filters-annotations")
+ .when()
+ .get("/endpoint2");
+
+ Optional customFilterLog = customFilterLogs.list.stream()
+ .filter(e -> e.getMessage()
+ .contains("request header:"))
+ .findFirst();
+ Optional requestIdFilterLog = requestIDFilterLogs.list.stream()
+ .filter(e -> e.getMessage()
+ .contains("request ID"))
+ .findFirst();
+ Optional privilegedUserFilterLog = privilegedUsersEndpointFilterLogs.list.stream()
+ .filter(e -> e.getMessage()
+ .contains("Privileged user was filtered"))
+ .findFirst();
+
+ assertThat(customFilterLog).isPresent();
+ assertThat(requestIdFilterLog).isPresent();
+ assertThat(privilegedUserFilterLog).isEmpty();
+ assertThat(customFilterLog.get()
+ .getNanoseconds()).isGreaterThan(requestIdFilterLog.get()
+ .getNanoseconds());
+ }
+
+ private static ListAppender getListAppenderForClass(Class> clazz) {
+ Logger logger = (Logger) LoggerFactory.getLogger(clazz);
+ ListAppender loggingEventListAppender = new ListAppender<>();
+ loggingEventListAppender.start();
+ logger.addAppender(loggingEventListAppender);
+
+ return loggingEventListAppender;
+ }
+}
diff --git a/microservices-modules/micronaut-configuration/src/test/java/com/baeldung/micronaut/httpfilters/ServerApplicationTest.java b/microservices-modules/micronaut-configuration/src/test/java/com/baeldung/micronaut/httpfilters/ServerApplicationTest.java
new file mode 100644
index 000000000000..5be31e36b853
--- /dev/null
+++ b/microservices-modules/micronaut-configuration/src/test/java/com/baeldung/micronaut/httpfilters/ServerApplicationTest.java
@@ -0,0 +1,98 @@
+package com.baeldung.micronaut.httpfilters;
+
+import static com.baeldung.micronaut.httpfilters.utils.CustomHttpHeaders.CUSTOM_HEADER_KEY;
+import static com.baeldung.micronaut.httpfilters.utils.CustomHttpHeaders.PRIVILEGED_USER_HEADER_KEY;
+import static com.baeldung.micronaut.httpfilters.utils.CustomHttpHeaders.REQUEST_ID_HEADER_KEY;
+import static com.baeldung.micronaut.httpfilters.utils.CustomHttpHeaders.X_TRACE_HEADER_KEY;
+import static org.hamcrest.Matchers.emptyOrNullString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.matchesPattern;
+
+import java.util.UUID;
+
+import org.junit.jupiter.api.Test;
+
+import io.micronaut.test.extensions.junit5.annotation.MicronautTest;
+import io.restassured.specification.RequestSpecification;
+
+@MicronautTest
+class ServerApplicationTest {
+
+ private static final String FILTERED_ENDPOINTS_PATH = "micronaut-configuration-tutorials/filters-annotations";
+
+ @Test
+ public void givenFilterForPrivilegedUsers_whenPrivilegedEndpointUsed_thenResponseContainsTag(RequestSpecification spec) {
+ spec.given()
+ .basePath(FILTERED_ENDPOINTS_PATH)
+ .when()
+ .get("/endpoint1")
+ .then()
+ .statusCode(200)
+ .body(is("Endpoint 1"))
+ .header(PRIVILEGED_USER_HEADER_KEY, "true");
+ }
+
+ @Test
+ public void givenFilterForPrivilegedUsers_whenNonPrivilegedEndpointUsed_thenResponseNotContainsTag(RequestSpecification spec) {
+ spec.given()
+ .basePath(FILTERED_ENDPOINTS_PATH)
+ .when()
+ .get("/endpoint2")
+ .then()
+ .statusCode(200)
+ .body(is("Endpoint 2"))
+ .header(PRIVILEGED_USER_HEADER_KEY, emptyOrNullString());
+ }
+
+ @Test
+ public void givenFilteredPath_whenRequestFiltered1_thenFilteredResponseReturned(RequestSpecification spec) {
+ spec.given()
+ .basePath(FILTERED_ENDPOINTS_PATH)
+ .header(CUSTOM_HEADER_KEY, "custom-value")
+ .when()
+ .get("/endpoint1")
+ .then()
+ .statusCode(200)
+ .body(is("Endpoint 1"))
+ .header(X_TRACE_HEADER_KEY, "true");
+ }
+
+ @Test
+ public void givenFilteredPath_whenRequestFiltered2_thenFilteredResponseReturned(RequestSpecification spec) {
+ spec.given()
+ .basePath(FILTERED_ENDPOINTS_PATH)
+ .when()
+ .get("/endpoint2")
+ .then()
+ .statusCode(200)
+ .body(is("Endpoint 2"))
+ .header(X_TRACE_HEADER_KEY, "true");
+ }
+
+ @Test
+ public void givenFilterWithContinuation_whenRequestIDNotInRequest_thenNewUUIDValuePassedInResponse(RequestSpecification spec) {
+ spec.given()
+ .basePath(FILTERED_ENDPOINTS_PATH)
+ .when()
+ .get("/endpoint1")
+ .then()
+ .statusCode(200)
+ .body(is("Endpoint 1"))
+ .header(REQUEST_ID_HEADER_KEY, matchesPattern("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"));
+ }
+
+ @Test
+ public void givenFilterWithContinuation_whenRequestIDInRequest_thenSameValuePassedInResponse(RequestSpecification spec) {
+ UUID requestId = UUID.randomUUID();
+
+ spec.given()
+ .basePath(FILTERED_ENDPOINTS_PATH)
+ .header(REQUEST_ID_HEADER_KEY, requestId)
+ .when()
+ .get("/endpoint1")
+ .then()
+ .statusCode(200)
+ .body(is("Endpoint 1"))
+ .header(REQUEST_ID_HEADER_KEY, requestId.toString());
+ }
+}
diff --git a/microservices-modules/pom.xml b/microservices-modules/pom.xml
index 74575c6c0eaa..199a618e70b9 100644
--- a/microservices-modules/pom.xml
+++ b/microservices-modules/pom.xml
@@ -17,6 +17,7 @@
helidon
micronaut
+ micronaut-configuration
micronaut-reactive
msf4j