1

I'm writing a Spring Boot application with several @Configuration classes for rest APIs and for Kafka consumers/producers depending on which @Profile it chooses to initialize.

The first configuration class uses the REST interface, and I have these dependencies added. This starts up an embedded Tomcat instance and runs fine.

Here the problem is the other profiles should not spin a tomcat server, it should act only as a Kafka consumer.

Is there any way to stop spinning the @SpringBootApplication from starting up Tomcat based on profiles?

I created 2 configuration classes, one for Kafka and one for rest endpoints, and added @Profile annotation for each config class. Can someone guide me on how to stop spin tomcat from my app?

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.0.RELEASE</version>
</parent>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-batch</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-cache</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <exclusions>
            <exclusion>
                <groupId>org.apache.tomcat</groupId>
                <artifactId>tomcat-jdbc</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

Main application:

@SpringBootApplication
@Import(value = {RestScanConfiguration.class, KafkaScanConfiguration.class})
public class MainApp {

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

RestScanConfiguration class:

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages = "package.app.rest")
@Profile("!kafka")
public class RestScanConfiguration {
}

KafkaScanConfiguration class:

 @Configuration
@EnableAutoConfiguration(
        exclude = {
                DataSourceAutoConfiguration.class,
                HibernateJpaAutoConfiguration.class,
                ElasticsearchDataAutoConfiguration.class
        })
@ComponentScan(basePackages = {"package.app.kafka"})
@Profile("kafka")
public class KafkaScanConfiguration {
}

can someone guide me on this?

How to stop spinning the tomcat server in Kafka consumer/producer profile. Any help would be appreciated.

Anjanaa
  • 468
  • 1
  • 4
  • 13
  • "Here the problem is the other profiles should not spin a tomcat server, it should act only as a Kafka consumer" - how do you plan on running the consumer, if not on a tomcat server or any other server? – SputNick Feb 09 '23 at 08:58

2 Answers2

0

First you have to disbale the auto configuration for the embeded tomcat in the starter class to avoid deploying the tomcat:

@SpringBootApplication(exclude = {EmbeddedServletContainerAutoConfiguration.class, 
                                  WebMvcAutoConfiguration.class})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

and then add the following property to your kafka config (non-Rest profiles):

spring.main.web-environment=false

now you have disabled auto-deployment of the integrated tomcat in spring boot. Now add the following configuration to your Rest profile to enable tomcat (only for this profile):

@Profile({"REST"})
@Configuration
// importing EmbeddedServletContainerAutoConfiguration delays the autoconfiguration until the profile load into context
@Import(EmbeddedServletContainerAutoConfiguration.class)
public class HttpConfiguration {
    // ...
}

and afterwards you have configure your kafka dynamically. You can find a solution for that in Control enabling/disabling Kafka consumers in Spring Boot

0

Instead of configuring this in code I'd suggest you to create application-kafka.properties (or application-kafka.yml) and add the following line into it:

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration

This disables ServletWebServerFactoryAutoConfiguration which is a root configuration class for Web environment.

-kafka suffix in properties file name tells Spring to pick it up only when kafka profile is active.

Even better solution is to exclude

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

from built jar. In other words you could have a pom.xml two profiles with only required dependencies (shared ones are located in main dependencies section). See https://stackoverflow.com/a/167284/12473843. Using this approach you don't even need specifying excluded autoconfigurations as without spring-boot-starter-web in the classpath corresponding started is never activated.

Sergey Tsypanov
  • 3,265
  • 3
  • 8
  • 34