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: INFO
application-dev.yml:
datasource:
url: jdbc:mysql://dev-db:3306/accounts
username: dev_user
application-qa.yml:
datasource:
url: jdbc:mysql://qa-db:3306/accounts
username: qa_user
application-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 ResponseEntity refreshConfig() {
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: