It seems that the routes are not being correctly registered when runing with default Tomcat in version 2.4.0

Sample code:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.Duration;
import java.time.LocalDateTime;

import static org.springframework.web.reactive.function.server.RequestPredicates.GET;
import static org.springframework.web.reactive.function.server.RouterFunctions.route;
import static org.springframework.web.reactive.function.server.ServerResponse.ok;

@SpringBootApplication
public class SpringBootFunctionalReactiveWithInterceptorsApplication {

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

    @Configuration
    static class RouterConfig {

        @Bean
        public RouterFunction<ServerResponse> timerRouterRunction(TestHandler testHandler) {
            return route(GET("/time"), testHandler::getTime).andRoute(GET("/times"), testHandler::sendTimePerSec);
        }

    }

    @Component
    static class TestHandler {

        public Mono<ServerResponse> getTime(ServerRequest serverRequest) {
            return ok().contentType(MediaType.TEXT_PLAIN).body(Mono.just("Now is " + LocalDateTime.now()),
                    String.class);
        }

        public Mono<ServerResponse> sendTimePerSec(ServerRequest serverRequest) {
            return ok().contentType(MediaType.TEXT_EVENT_STREAM)
                    .body(Flux.interval(Duration.ofSeconds(1)).map(l -> LocalDateTime.now().toString()), String.class);
        }

    }
}

Test case:

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.reactive.server.WebTestClient;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class SpringBootFunctionalReactiveWithInterceptorsApplicationTests {

    @Autowired
    private  WebTestClient client;

    @Test
    void contextLoads() {
        client.get().uri("/time").exchange().expectStatus().isOk();
    }

    @Test
    void actuatorLoads() {
        client.get().uri("/actuator").exchange().expectStatus().isOk();
    }

}

contextLoads will fail while actuatorLoads will pass.

Comment From: DarekDan

It might be that spring-boot-starter-parent implies use of spring-boot-starter-web, which relies on Tomcat. After adding an exclusion, the service is operational.

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>tomcat-embed-el</artifactId>
                    <groupId>org.apache.tomcat.embed</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>tomcat-embed-core</artifactId>
                    <groupId>org.apache.tomcat.embed</groupId>
                </exclusion>
                <exclusion>
                    <artifactId>tomcat-embed-websocket</artifactId>
                    <groupId>org.apache.tomcat.embed</groupId>
                </exclusion>
            </exclusions>
        </dependency>

Comment From: DarekDan

Is there a way to run WebFlux Reactive Functions on Tomcat? What configuration steps am I missing?

Comment From: bclozel

Could you show your entire POM file please? The spring-boot-starter-web dependency is for building Spring MVC applications. If on the classpath, Spring Boot will assume you're building one and that the WebFlux dependency is here for using the WebClient (this is documented in the reference documentation).

If you'd like to build a reactive web application, the spring-boot-starter-webflux dependency should be enough. If you'd like to switch to Tomcat, adding spring-boot-starter-tomcat should work.

Comment From: DarekDan

Here it is:

``` org.springframework.boot spring-boot-starter-parent 2.4.0 ... 1.8

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <exclusions>
            <exclusion>
                <artifactId>tomcat-embed-el</artifactId>
                <groupId>org.apache.tomcat.embed</groupId>
            </exclusion>
            <exclusion>
                <artifactId>tomcat-embed-core</artifactId>
                <groupId>org.apache.tomcat.embed</groupId>
            </exclusion>
            <exclusion>
                <artifactId>tomcat-embed-websocket</artifactId>
                <groupId>org.apache.tomcat.embed</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <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>
    <dependency>
        <groupId>org.springframework.restdocs</groupId>
        <artifactId>spring-restdocs-webtestclient</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>

```

Comment From: snicoll

As Brian has indicated, if you bring both spring-boot-starter-web and spring-boot-starter-webflux your app runs in servlet mode. If you intend to use Webflux.fn in a reactive web application, only spring-boot-starter-webflux is necessary.

See the documentation and this question to run webflux on Tomcat for more details.

Comment From: DarekDan

One small comment, initially I did not have the spring-boot-starter-web artifact, and only added it to remove Tomcat dependency.

Comment From: snicoll

You won't get Tomcat unless you add spring-boot-starter-web.

Comment From: DarekDan

This was closed prematurely.

Comment From: DarekDan

I do get Tomcat with the above pom.xml without spring-boot-starter-web dependency explicitly mentioned. Try it. :)

Comment From: bclozel

spring-boot-starter-data-rest is based on Spring MVC, and thus depends on spring-boot-starter-web.

Comment From: DarekDan

Thank you!