Java Spring Boot

Dynamic Environment Configuration in Spring Boot Using Profiles

In This Article

Learn how to use Spring Boot profiles to manage environment-specific services and configurations, ensuring flexibility and reducing deployment errors.

In a typical software development lifecycle, applications need to adapt to various environments like development, testing, and production. Each environment has its own specific configurations, such as database connections, messaging services, or even simple greeting messages. Instead of hardcoding these settings, Spring Boot offers a powerful feature called Profiles, which allows you to define and load environment-specific configurations dynamically. This blog post will show you how to create a simple Spring Boot application that prints different messages depending on whether it’s running in a local or production environment.

Scenario: Switching Between Local and Production Services

We will create two services, each printing a different message. The service used will depend on whether the application is running in a local environment or in production. This will demonstrate the flexibility of Spring profiles for environment-specific behavior.

Step 1: Define a Simple Service Interface

First, we’ll create an interface that both the local and production implementations will adhere to:

public interface GreetingService {
    void printMessage();
}
Java

Step 2: Add Environment-Specific Configurations in application.properties

We’ll use separate configuration files for local and production environments, with a default application.properties file to specify the active profile.

application.properties:

# Default profile
spring.profiles.active=local

application-local.properties:

spring.profiles.active=local

application-prod.properties:

spring.profiles.active=prod

Step 3: Implement the Local Greeting Service

Now, implement the GreetingService for the local environment:

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

@Service
@Profile("prod")
public class ProdGreetingService implements GreetingService {

    @Override
    public void printMessage() {
        System.out.println("Welcome to the Production Environment");
    }
}
Java

Step 4: Implement the Production Greeting Service

Similarly, implement the GreetingService for the production environment:

import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Service;

@Service
@Profile("prod")
public class ProdGreetingService implements GreetingService {

    @Override
    public void printMessage() {
        System.out.println("Welcome to the Production Environment");
    }
}
Java

Step 5: Use the Greeting Service in Your Application

Next, create a service that uses the GreetingService to print the appropriate message based on the active profile:

import org.springframework.stereotype.Service;

@Service
public class MessageService {

    private final GreetingService greetingService;

    public MessageService(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    public void printEnvironmentMessage() {
        greetingService.printMessage();
    }
}
Java

Step 6: Running the Application

  • Local Environment: To run your application with the local profile, the default configuration will work since we’ve set spring.profiles.active=local in application.properties.
  • Production Environment: To switch to the production profile, you can override the active profile by setting the following in your application-prod.properties or through command-line arguments when starting the application:
spring.profiles.active=prod
Plaintext

Testing the Greeting Service

When writing unit tests, you can mock the GreetingService to test how your MessageService behaves without relying on the actual environment:

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;

import static org.mockito.Mockito.*;

class MessageServiceTest {

    @Test
    void testPrintEnvironmentMessage() {
        // Arrange
        GreetingService mockGreetingService = mock(GreetingService.class);
        MessageService messageService = new MessageService(mockGreetingService);

        // Act
        messageService.printEnvironmentMessage();

        // Assert
        verify(mockGreetingService).printMessage();
    }
}
Java

Conclusion

Using Spring profiles and environment-specific configuration files, you can easily switch between different services or settings depending on the environment your application is running in. This approach ensures that your application remains flexible and adaptable, minimizing the need for code changes when moving between development and production environments.