Spring Boot provides multiple ways to read properties from configuration files like application.properties
or application.yml
. These properties can be accessed in your application using various approaches depending on the use case.
The @Value
annotation is used to inject a single property value into a field.
@RestController public class MyController { @Value("${app.name}") private String appName; @GetMapping("/app-name") public String getAppName() { return appName; } }
Explanation: The @Value
annotation injects the value of app.name
from application.properties
.
# application.properties app.name=My Spring Boot App
The @ConfigurationProperties
annotation binds a group of properties into a Java class.
@Component @ConfigurationProperties(prefix = "app") public class AppConfig { private String name; private String version; // Getters and Setters } @RestController public class MyController { private final AppConfig appConfig; public MyController(AppConfig appConfig) { this.appConfig = appConfig; } @GetMapping("/app-info") public String getAppInfo() { return "Name: " + appConfig.getName() + ", Version: " + appConfig.getVersion(); } }
Explanation: The @ConfigurationProperties
binds all properties with the prefix app
into the AppConfig
class.
# application.properties app.name=My Spring Boot App app.version=1.0.0
The Environment
object can be used to programmatically fetch property values.
@RestController public class MyController { private final Environment environment; public MyController(Environment environment) { this.environment = environment; } @GetMapping("/app-description") public String getAppDescription() { return environment.getProperty("app.description"); } }
Explanation: The Environment
object retrieves the value of app.description
at runtime.
# application.properties app.description=This is a Spring Boot application.
The @PropertySource
annotation is used to load properties from an external file.
@Configuration @PropertySource("classpath:custom.properties") public class CustomConfig { @Value("${custom.property}") private String customProperty; public String getCustomProperty() { return customProperty; } } @RestController public class MyController { private final CustomConfig customConfig; public MyController(CustomConfig customConfig) { this.customConfig = customConfig; } @GetMapping("/custom-property") public String getCustomProperty() { return customConfig.getCustomProperty(); } }
Explanation: The @PropertySource
annotation loads properties from the custom.properties
file.
# custom.properties custom.property=Custom Value
Properties can also be loaded and injected into beans.
@Configuration public class AppConfig { @Bean public String appName(@Value("${app.name}") String appName) { return appName; } } @RestController public class MyController { private final String appName; public MyController(String appName) { this.appName = appName; } @GetMapping("/bean-app-name") public String getBeanAppName() { return appName; } }
Explanation: This approach uses a bean to inject the property value, which can then be used in the application.
Each method has its own use case. Use @Value
for single properties, @ConfigurationProperties
for grouped properties, and Environment
for programmatic access. The @PropertySource
annotation and Bean configuration provide additional flexibility for loading and injecting properties.
You're developing a microservice called Account Service using Spring Boot. The application needs to be deployed across multiple environments (dev, qa, prod) with different configurations. The goal is to:
To address these challenges, we'll use Spring Boot profiles and externalize configurations:
Create application.yml
for common settings and environment-specific files (application-dev.yml
, application-qa.yml
, application-prod.yml
) for custom properties.
spring: application: name: account-service logging: level: root: INFOapplication-dev.yml:
datasource: url: jdbc:mysql://dev-db:3306/accounts username: dev_userapplication-qa.yml:
datasource: url: jdbc:mysql://qa-db:3306/accounts username: qa_userapplication-prod.yml:
datasource: url: jdbc:mysql://prod-db:3306/accounts username: prod_user
Use AWS Secrets Manager to securely store sensitive data like database passwords.
account-service-dev-db-creds
, account-service-qa-db-creds
, account-service-prod-db-creds
).Use Spring Cloud Config Server to pull properties from a Git repository:
config-repo/ account-service-dev.yml account-service-qa.yml account-service-prod.yml
Now, let's set up a Jenkins pipeline to automate builds and deployments:
Create a parameterized Jenkins job with a dropdown to select the target environment:
parameters { choice(name: 'ENVIRONMENT', choices: ['dev', 'qa', 'prod'], description: 'Select the deployment environment') }
environment { SPRING_PROFILES_ACTIVE = "${params.ENVIRONMENT}" }
stage('Checkout Code') { steps { checkout scm } }
stage('Build') { steps { sh 'mvn clean package' } }
stage('Deploy') { steps { sh "java -Dspring.profiles.active=${SPRING_PROFILES_ACTIVE} -jar target/account-service.jar" } }
When the pipeline is executed:
qa
) from the Jenkins job dropdown.SPRING_PROFILES_ACTIVE
to qa
and starts the deployment process.To handle sensitive credentials securely:
@Configuration public class SecretsConfig { @Bean public String dbPassword() { AWSSecretsManager secretsManager = AWSSecretsManagerClientBuilder.standard() .withRegion("us-east-1") .build(); String secretValue = secretsManager.getSecretValue(new GetSecretValueRequest() .withSecretId("account-service-" + System.getProperty("spring.profiles.active") + "-db-creds")) .getSecretString(); return new JSONObject(secretValue).getString("password"); } }
For Kubernetes deployment:
SPRING_PROFILES_ACTIVE
as an environment variable in the deployment YAML:env: - name: SPRING_PROFILES_ACTIVE value: "qa"
To allow the application to refresh its configurations dynamically without redeploying:
@SpringBootApplication @EnableConfigServer @EnableDiscoveryClient @EnableAutoConfiguration public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }
@SpringBootApplication @EnableSpringCloudBus @EnableConfigServer @EnableDiscoveryClient public class AccountServiceApplication { public static void main(String[] args) { SpringApplication.run(AccountServiceApplication.class, args); } }
spring: cloud: config: monitor: enabled: true bus: refresh: applications: account-service
@RestController public class ConfigRefreshController { private final ConfigurableApplicationContext context; @Autowired public ConfigRefreshController(ConfigurableApplicationContext context) { this.context = context; } @GetMapping("/refresh") public ResponseEntityrefreshConfig() { context.publishEvent(new RefreshEvent(this)); return ResponseEntity.ok("Configuration refreshed!"); } }
The /refresh
endpoint can be triggered manually via a Jenkins job or automatically upon detecting changes in the Git repository monitored by Spring Cloud Config Monitor:
/refresh
endpoint./refresh
endpoint by accessing the endpoint URL through a browser or a REST client.With the pipeline in place:
The team now enjoys: