Environment-Dependent Code Execution with Spring Boot and Docker

Different deployment environments (e.g., development, testing, staging and production) often require that different pieces of code are switched on and off. For example, you only want to send real emails in production and write to an email log in all other environments instead. Or your code to initialise the database should only run in the staging environment.

A simple but hard to maintain way for such conditional code executions is to define a globally available variable such as isProductionSystem and write code such as this:

if (isProductionSystem) {
  sendMail(...);
} else {
  logMail(...);
}

This is hard to maintain because you end up with large if statements if you have multiple environments. Also, the only way you can adapt in your environment is to change the isProductionSystem variable, which means you either have all of the “production-only” features or none of them.

The @ConditionalOnProperty Annotation

Spring offers a much better way to handle conditional code execution. You can annotate the beans that should only execute depending on an environment flag with the ConditionalOnProperty annotation:

@Bean
@ConditionalOnProperty(value = "emails.enabled")
public EmailJob emailJob() {
    return new EmailJob();
}

In the above example, the email job is only started when the property-value emails.enabled is set to true.

Profile-dependent execution

The code execution can also be dependent on the application profile:

@Profile("prod")
@Bean
public emailJob emailJob() {
    return new EmailJob();
}

As already mentioned, this removes some level of flexibility because you can no longer decide to activate or deactivate individual features at configuration time on the respective environment.

Overriding Configuration Flags in Docker

When using Docker, you can override the default values for the properties by using environment variables with the -e flag of the docker run command:

docker run -it -e SPRING_JPA_DATABASE_PLATFORM=org.hibernate.dialect.PostgreSQLDialect myimage:latest

Spring translates environment variables into the dot-syntax for property-names by substituting dots with underscores and capitalising everything. If you want to override the value of my.property, you need to set the environment variable MY_PROPERTY.

In the above example, you can control whether to actually send emails with the following command:

docker -it -e EMAILS_ENABLED=1 myapp:latest

Conditional Execution on Application Startup

There is another interesting use case for an overridable configuration switch: code that is executed on application startup. For example, a method that creates test instances in an empty database in the staging system but is skipped in production.

This is more verbose but is still readable. Simply extract the configuration value with the @Value annotation (with the default false) into a private variable and check it in a method annotated with the @EventListener annotation listening to the ApplicationReadyEvent:

@Service
public class PostStartService {

    @Value("${init.empty.db:false}")
    private boolean initEmptyDb;

    @EventListener(ApplicationReadyEvent.class)
    public void createTestData() {
        if (!initEmptyDb) {
            return;
        }

        // execute your code here
    }
}

In the above code snippet, you can control whether the body of createTestData is executed via setting the following environment variable in Docker:

docker -it -e INIT_EMPTY_DB=1 myapp:latest

Conclusion

In this article, I presented several techniques to run code depending on the deployment environment. Let me know how what works best for you or if you have different ways of achieving the correct environment configuration.

Thymeleaf: Output Size of List

Question: In my Thymeleaf template, I want to output the size of a list of objects. For example, for the list

List<String> list = Arrays.asList("Go", "Python", "Scala");

the result should be 3. How is this possible using just Thymeleaf syntax?

You can use the following expression:

<span th:text="${#lists.size(myList)}">[Number of Elements]</span>

And just in case you want to check if the list is empty, there is also an easy method for that:

<span th:if="${#lists.isEmpty(myList)}">This list is empty</span>

Send JSON objects via POST to Spring Boot Controllers

Creating and persisting business objects using Spring Boot is amazingly easy. Assume you create an API for simple CRUD methods and want to create an entity based on data entered by your frontend users. In the old times, you would probably populate several POST fields in a key-value style and create your business object manually from those fields.

Spring Boot offers an easier solution. As long as your internal data model equals the frontend’s data model, you can use the @Valid On @RequestBody Controller Method Arguments to automatically create the object from a JSON-serialized request and execute the necessary validation logic.

Continue reading

Creating a VirtualBox-Based Spring Boot Development Environment

In this article, I’ll show how to set up a simple development environment for working with Spring Boot inside a VirtualBox Ubuntu Server. You will learn how to

  • configure port forwarding for interacting with the development server
  • set up shared folders for using an IDE on your client to edit code on the server
  • build and execute the application using maven

Let’s get started!

Prerequisites

You need:

Continue reading