Open In App

Spring WebFlux (Mono/Flux) with AOP Triggering REST Call at Interception and Working with Mono/Flux

Last Updated : 23 Jul, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Spring WebFlux is a component of the Spring Framework that supports reactive programming. It enables developers to build asynchronous, non-blocking applications. WebFlux uses Project Reactor as its reactive library and introduces two main types: Mono and Flux. Aspect-Oriented Programming (AOP) in Spring allows for the separation of cross-cutting concerns such as logging or transaction management. By combining WebFlux with AOP, we can trigger REST calls within the AOP interceptor and handle the results using reactive types.

This article will guide you on how to set up a Spring WebFlux project with AOP to trigger REST calls during method interception and handle these calls using Mono and Flux.

Spring WebFlux Overview

Spring WebFlux is built on reactive principles, enabling applications to handle massive concurrency with fewer resources compared to traditional blocking architectures.

  • Mono: Represents a single, possibly empty, asynchronous sequence of 0 or 1 element.
  • Flux: Represents a sequence of 0 to N elements.

Aspect-Oriented Programming (AOP)

AOP is a programming paradigm that allows for the separation of concerns by enabling the addition of behavior to existing code without modifying it. Spring AOP is typically used for cross-cutting concerns like logging, security, and transaction management.

  • Aspect: The modularization of a concern that cuts across multiple classes.
  • Advice: The action taken by an aspect at a specific join point is known as advice. Types include Before, After, AfterReturning, AfterThrowing, and Around.
  • Join Point: A specific point in the execution of a program, such as when a method is called or an exception is handled.
  • Pointcut: The pointcut expression defines the predicate used to match join points. Advice is linked to this pointcut expression and executes at each join point that the pointcut expression matches.

Combining WebFlux and AOP

By leveraging AOP in a WebFlux application, we can intercept method calls and trigger asynchronous REST requests. This approach is useful in scenarios where actions such as logging or auditing require data from external services.

Spring AOP Annotations:

  • @Aspect: Declares the class as an aspect.
  • @Pointcut: Declares the pointcut expression.
  • @Before: Advice that runs before the matched method's execution.
  • @AfterReturning: Advice that runs after the matched method successfully returns.
  • @AfterThrowing: Advice that runs if the matched method throws an exception.
  • @Around: Advice that runs before and after the matched method's execution.

Integrating Spring WebFlux with AOP for Asynchronous REST Calls

External API Implementation

Step 1: Create the New Spring Boot Project

Create a new spring boot project using intelliJ idea and choose the below options:

  • Name: external-API
  • Language: Java
  • Type: Maven
  • Packaging: jar

Click on the Next button.

Project Metadata

Step 2: Add the Dependencies

Add the following dependencies to the project and click the "Create" button. Refer to the provided image for better understanding.

Add Dependencies


Once the project is created, the file structure will look like the provided image.

Project Folder Structure


Step 3: Create the ExternalApiController Class

Create a simple endpoint to expose the external API of the project.

Navigate to src > main > java > com.gfg.externalapi and create ExternalApiController with the following code:

Java
package com.gfg.externalapi;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * Controller for handling external API requests.
 */
@RestController
public class ExternalApiController {

    /**
     * Endpoint to fetch data.
     *
     * @return DataResponse containing sample data.
     */
    @GetMapping("/data")
    public DataResponse getData() {
        return new DataResponse("Sample data from external API");
    }

    /**
     * DataResponse class to encapsulate the response message.
     */
    public static class DataResponse {
        private String message;

        /**
         * Constructor to initialize the DataResponse with a message.
         *
         * @param message the response message.
         */
        public DataResponse(String message) {
            this.message = message;
        }

        /**
         * Getter for the message.
         *
         * @return the response message.
         */
        public String getMessage() {
            return message;
        }

        /**
         * Setter for the message.
         *
         * @param message the response message to set.
         */
        public void setMessage(String message) {
            this.message = message;
        }
    }
}


Step 4: Main Class

No changes are required in the main class. The code for the main class is:

Java
package com.gfg.externalapi;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ExternalApiApplication {

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

}


pom.xml

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg</groupId>
    <artifactId>external-API</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>external-API</name>
    <description>external-API</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

Step 5: Run the Application

Once completed the application, it will run and start at port 8080.

ex4-compressed

Spring AOP Project Implementation

Step 1: Create the new Spring Reactive Project

We can create the new Spring Reactive project using the IntelliJ Idea. Choose the below options:

  • Name: weblux-aop-demo
  • Language: Java
  • Type: Maven
  • packaging: jar

Click on the Next button

ex5

Step 2: Add the Dependencies

We can add the below dependencies into the project.Refer the below image for better understanding.

ex6

Once create the project then the file structure looks like the below image.

exx12

Step 3: Create the ExternalService Class

We can create the simple service class named as ExternalService class

Go to src > main > java > com.gfg.webfluxaopdemo > ExternalService and put the below code.

Java
package com.gfg.webfluxaopdemo;

import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;



@Service
public class ExternalService {

    private final WebClient webClient;

    public ExternalService(WebClient.Builder webClientBuilder) {
        this.webClient = webClientBuilder.baseUrl("http://localhost:8080").build();
    }

    public Mono<String> getExternalData() {
        return webClient.get()
                .uri("/data")
                .retrieve()
                .bodyToMono(DataResponse.class)
                .map(DataResponse::getMessage);
    }

    private static class DataResponse {
        private String message;

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }
}

Step 4: Create the LoggingAspect Class

Go to src > main > java > com.gfg.webfluxaopdemo > LoggingAspect and put the below code.

Java
package com.gfg.webfluxaopdemo;

import com.gfg.webfluxaopdemo.ExternalService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LoggingAspect {

    private final ExternalService externalService;

    @Pointcut("execution(* com.gfg.webfluxaopdemo.*.*(..))")
    public void controllerMethods() {}

    @Pointcut("execution(* com.gfg.webfluxaopdemo.ExternalService.*(..))")
    public void externalServiceMethods() {}

    @AfterReturning(pointcut = "controllerMethods() && !externalServiceMethods()", returning = "result")
    public void logAfterMethodReturn(Object result) {
        Mono<String> response = externalService.getExternalData();
        response.subscribe(data -> log.info("Data from external service: {}", data));
    }
}

Step 5: Create the DemoController Class

Go to src > main > java > com.gfg.webfluxaopdemo > DemoController and put the below code.

Java
package com.gfg.webfluxaopdemo;


import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;

@RestController
public class DemoController {

    @GetMapping("/hello")
    public Mono<String> sayHello() {
        return Mono.just("Hello, WebFlux with AOP!");
    }
}

Step 6: Main Class

No changes are required in the main class

Java
package com.gfg.webfluxaopdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebfluxAopDemoApplication {

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

}

pom.xml

XML
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg</groupId>
    <artifactId>webflux-aop-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>webflux-aop-demo</name>
    <description>webflux-aop-demo</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


Step 7: Run the application

Once the project is complete, it will run and start on port 8081.

Application Runs


Step 8: Testing the Application

Test the endpoints using Postman:

GET http://localhost:8081/hello

Output:

hello Endpoint Testing


Logs Result

Refer to the provided image for the logs result.

Logs Result

Conclusion

In this article, we explored how to set up a Spring WebFlux project with AOP to trigger REST calls during method interception and handle these calls using Mono and Flux. This approach provides a powerful and flexible way to integrate cross-cutting concerns with reactive programming.


Explore