Appearance
Application properties
This document provides a comprehensive guide to configuring the application using Spring Boot's property management system. A deep understanding of these principles is crucial for development, deployment, and maintenance, especially given the project's strategy of relying on externalized configuration for cloud migration.
Overview
The application leverages Spring Boot's powerful externalized configuration mechanism, which allows the application's behavior to be modified across different environments without changing the source code. The primary configuration file is src/main/resources/application.properties.
Property Hierarchy and Precedence
Spring Boot loads properties from various sources with a specific order of precedence. A property defined in a location with higher precedence will override one from a location with lower precedence. The most common sources, from lowest to highest precedence, are:
- Default properties (internal to Spring Boot).
- Properties files packaged inside the JAR (
application.propertiesand profile-specific variants). - Operating system environment variables.
- Command-line arguments passed to
java -jar.
This hierarchy is fundamental to the application's migration strategy, allowing environment-specific settings (like those in Google Cloud) to override the default, on-premises configuration.
Environment-Specific Configuration and Spring Profiles
Spring Profiles are used to segregate parts of the application configuration and make them available only in certain environments. The active profile is determined by the spring.profiles.active property.
For example, the project includes application-local.properties, which is activated when the local profile is enabled (e.g., by setting the JVM argument -Dspring.profiles.active=local). This file contains overrides suitable for a developer's local machine, such as connecting to a local database and enabling more verbose logging.
When a profile (e.g., local) is active, Spring Boot will load properties from both application.properties and application-local.properties. Properties defined in application-local.properties will override those in the default file.
Core settings
These are the fundamental properties that define the application's identity, runtime behavior, and default service connections.
Application Name and Server Port
The application's name and the port for the embedded Tomcat server are defined in src/main/resources/application.properties.
properties
# Application Configuration
# Defines the application name used by Spring Boot for various purposes, including logging and Actuator endpoints.
spring.application.name=it-ticketing-service
# The port on which the embedded Tomcat server will listen for HTTP requests.
server.port=80801
2
3
4
5
6
2
3
4
5
6
Service Connection Defaults
The default application.properties file contains connection details for the legacy, on-premises environment.
properties
# src/main/resources/application.properties
# MySQL Database Configuration
spring.datasource.url=jdbc:mysql://legacydb.next26.slalomlab.com:3306/ticketing?createDatabaseIfNotExist=true
spring.datasource.username=ticketing_user
spring.datasource.password=changeme # WARNING: Placeholder password, should be externalized.
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA/Hibernate Configuration
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=false
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect
spring.jpa.properties.hibernate.format_sql=true
# RabbitMQ Configuration
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
# RabbitMQ Custom Properties
rabbitmq.exchange.name=ticket.exchange
rabbitmq.queue.name=ticket.queue
rabbitmq.routing.key=ticket.routing.key1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Key Configuration Details:
- Database Driver: The MySQL JDBC driver class is explicitly specified for clarity.
- JPA/Hibernate DDL Auto: Set to
update, which automatically updates the database schema based on entity changes. This is suitable for development but should be carefully managed in production. - Show SQL: Set to
falseto prevent SQL statement logging in the console (can be enabled for debugging). - Hibernate Dialect: Configured for MySQL to optimize generated SQL.
- RabbitMQ Custom Properties: Defines the exchange name, queue name, and routing key used by the application's messaging logic.
For more detailed information on configuring these services, please refer to the Database Configuration and RabbitMQ Configuration documentation.
Logging Levels
Logging levels can be configured per package to control the verbosity of the application logs. The default configuration sets a baseline INFO level, while the local profile uses DEBUG for more detailed output during development.
Default Configuration (application.properties)
properties
# Logging Configuration
logging.level.com.slalom.demo.ticketing=INFO
logging.level.org.springframework.amqp=INFO
logging.level.org.springframework.web=INFO1
2
3
4
2
3
4
Local Development Override (application-local.properties)
properties
# Logging Configuration
logging.level.com.slalom.demo.ticketing=DEBUG
logging.level.org.springframework.amqp=DEBUG
logging.level.org.springframework.web=DEBUG1
2
3
4
2
3
4
This pattern allows developers to see detailed framework and application logs locally without cluttering the logs in deployed environments.
Actuator Endpoints
Spring Boot Actuator provides production-ready features for monitoring and managing the application. The default configuration exposes health and info endpoints with detailed health information.
Default Configuration (application.properties)
properties
# Actuator Configuration
management.endpoints.web.exposure.include=health,info
management.endpoint.health.show-details=always1
2
3
2
3
Local Development Override (application-local.properties)
properties
# Actuator Configuration
management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always1
2
3
2
3
management.endpoints.web.exposure.include: Specifies which actuator endpoints are exposed over HTTP. Onlyhealthandinfoendpoints are enabled by default for security. The local profile additionally exposes themetricsendpoint for development and debugging.management.endpoint.health.show-details: Set toalwaysto show detailed health information, including database and RabbitMQ connection status.
The health endpoint is accessible at http://localhost:8080/actuator/health and provides real-time status of the application and its dependencies.
Externalized configuration
As outlined in the project's architectural guidelines, maximizing externalized configuration is a core principle. This approach, aligned with 12-Factor App principles, is key to enabling a seamless migration to Google Cloud with minimal code changes. The application is designed to be configured entirely at runtime through external sources.
For more context on this strategy, see the Cloud Migration Strategy document.
Environment Variables
Using environment variables is the preferred method for supplying configuration in containerized and cloud environments like Google Cloud Run or GKE. Spring Boot automatically maps environment variables to application.properties keys.
The conversion rule is:
- Uppercase letters
- Replace dots (
.) with underscores (_) - Replace hyphens (
-) with underscores (_)
For example, to override the database URL and password, you would set the following environment variables:
bash
export SPRING_DATASOURCE_URL="jdbc:mysql://<gcp-cloud-sql-ip>:3306/ticketing"
export SPRING_DATASOURCE_PASSWORD="<your-secret-password-from-secret-manager>"1
2
2
These variables will take precedence over the values in the application.properties file inside the packaged application.
Command-Line Arguments
Properties can also be passed directly when running the application. This is useful for quick overrides or testing. Command-line arguments have higher precedence than environment variables.
bash
java -jar target/it-ticketing-service-0.0.1-SNAPSHOT.jar --server.port=9090 --logging.level.com.slalom.demo.ticketing=TRACE1
Configuration Server Integration
For more complex microservices landscapes, integrating with a configuration server like Spring Cloud Config or HashiCorp Consul is a common pattern. While not currently implemented, the application's design makes it straightforward to add a spring-cloud-starter-config dependency and point it to a central configuration repository. This would be a logical next step for managing configuration across many services in a production cloud environment.
Best practices
Adhering to these best practices is critical for maintaining a secure, flexible, and maintainable application.
1. Never Commit Secrets to Version Control
The default application.properties file contains a placeholder password:
properties
# WARNING: This is a security risk and is only for demonstrating the legacy setup.
spring.datasource.password=changeme1
2
2
This is an anti-pattern. In a real-world scenario, secrets must never be committed to a Git repository in plain text. The presence of this placeholder serves to highlight the legacy state that will be improved upon during cloud migration.
2. Use Environment Variables or Secret Management for Sensitive Data
The correct way to handle secrets is to inject them into the application's environment at runtime.
- For Local Development: Use an untracked
application-local.propertiesfile or set environment variables in your IDE's run configuration. - For Deployed Environments (e.g., Google Cloud): Integrate with a secret management service like Google Secret Manager. The application can be configured to fetch secrets at startup and supply them as environment variables to the running container.
3. Use Profile-Specific Property Files for Environment Differences
Maintain a clear separation of concerns between environments by using profile-specific files. This project demonstrates the pattern with application-local.properties. A typical production setup might include:
application.properties(contains common, non-sensitive defaults)application-dev.properties(for a shared development environment)application-qa.properties(for the testing team)application-prod.properties(contains production-specific settings, but no secrets)
By following these configuration principles, the application remains portable, secure, and easy to manage across its entire lifecycle, from local development to production deployment in the cloud.