Spring Core - Properties and Profiles
Use External Properties to control Configuration
1. Add Property File
Create a property file (e.g., application.properties) in the src/main/resources directory.
// application.properties
app.name=My Spring Application
app.version=1.0.0
app.server.port=8080
2. Enable Property Sources
By default, Spring Boot automatically loads application.properties or application.yml from the src/main/resources directory. For plain Spring projects (without Boot), use the @PropertySource annotation to specify the file.
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {
}
3. Inject Property Values Using @Value
Use the @Value annotation to inject values from the properties file into Spring beans.
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class AppProperties {
@Value("${app.name}")
private String appName;
@Value("${app.version}")
private String appVersion;
@Value("${app.server.port}")
private int serverPort;
public void printProperties() {
System.out.println("App Name: " + appName);
System.out.println("App Version: " + appVersion);
System.out.println("Server Port: " + serverPort);
}
}
4. Using @ConfigurationProperties for Structured Mapping
For managing complex property structures, you can use @ConfigurationProperties.
- Enable Configuration Properties: Add the @EnableConfigurationProperties annotation to your configuration class.
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "app")
public class AppConfigProperties {
private String name;
private String version;
private int serverPort;
// Getters and Setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getVersion() { return version; }
public void setVersion(String version) { this.version = version; }
public int getServerPort() { return serverPort; }
public void setServerPort(int serverPort) { this.serverPort = serverPort; }
}
- Access the Properties: You can inject this configuration class wherever needed.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class AppPropertiesPrinter {
private final AppConfigProperties properties;
@Autowired
public AppPropertiesPrinter(AppConfigProperties properties) {
this.properties = properties;
}
public void printProperties() {
System.out.println("App Name: " + properties.getName());
System.out.println("App Version: " + properties.getVersion());
System.out.println("Server Port: " + properties.getServerPort());
}
}
5. Using Profiles for Environment-Specific Properties
Spring allows you to define properties for specific environments using profiles (e.g., dev, prod).
- Create Profile-Specific Properties Files:
- application-dev.properties
- application-prod.properties
// application-dev.properties
app.name=My App (Development)
app.server.port=8081
// application-prod.properties
app.name=My App (Production)
app.server.port=8080
2. Activate a Profile:
- Set the active profile using the spring.profiles.active property.
- Add it to application.properties or pass it as a JVM argument (-Dspring.profiles.active=dev).
// Setting in application.properties
spring.profiles.active=dev
6. Load Properties Programmatically (Optional)
If needed, you can load properties programmatically using the Environment object.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
@Component
public class EnvironmentProperties {
@Autowired
private Environment environment;
public void printProperties() {
String appName = environment.getProperty("app.name");
String appVersion = environment.getProperty("app.version");
int serverPort = Integer.parseInt(environment.getProperty("app.server.port"));
System.out.println("App Name: " + appName);
System.out.println("App Version: " + appVersion);
System.out.println("Server Port: " + serverPort);
}
}
Advantages of Externalized Configuration
- Environment Flexibility: Easily switch between environments (e.g., dev, prod).
- Separation of Concerns: Keeps configuration separate from code.
- Ease of Management: Changes to configuration do not require code changes or recompilation.
Profiles: Support for environment-specific configuration through profiles.
Demonstrate the purpose of Profiles
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
@Configuration
@Profile("dev")
public class DevConfig {
@Bean
public DataSource dataSource() {
System.out.println("Development DataSource configured");
return new DataSource("jdbc:dev-url", "dev-user", "dev-password");
}
}
@Configuration
@Profile("prod")
public class ProdConfig {
@Bean
public DataSource dataSource() {
System.out.println("Production DataSource configured");
return new DataSource("jdbc:prod-url", "prod-user", "prod-password");
}
}
Use the Spring Expression Language (SpEL)
1. Injecting Values in Beans
SpEL expressions can dynamically set values in bean properties and method parameters using the @Value annotation.
@Component
public class SpELExample {
@Value("#{20 + 30}") // Basic math expression
private int sum;
@Value("#{T(Math).PI}") // Accessing static fields and methods
private double pi;
@Value("#{1 > 0 ? 'yes' : 'no'}") // Ternary operator
private String condition;
@Value("#{myBean.value}") // Accessing another bean's property
private String otherBeanValue;
// Getters
public int getSum() { return sum; }
public double getPi() { return pi; }
public String getCondition() { return condition; }
}
public class SimpleMovieLister {
private MovieFinder movieFinder;
private String defaultLocale;
@Autowired
public void configure(MovieFinder movieFinder,
@Value("#{ systemProperties['user.region'] }") String defaultLocale) {
this.movieFinder = movieFinder;
this.defaultLocale = defaultLocale;
}
// ...
}
2. Accessing Properties
You can use SpEL to inject values from property files.
// application.properties
app.timeout=5000
// Inject Property Using SpEL
@Value("#{${app.timeout}}")
private int timeout;
3. Conditional Expressions
SpEL supports conditional logic inside annotations.
@Value("#{systemProperties['os.name'].toLowerCase().contains('windows') ? 'Windows' : 'Non-Windows'}")
private String operatingSystem;
4. Bean References
SpEL allows referencing and calling methods on beans.
@Value("#{myService.calculateValue()}") // Call a method on a bean
private int calculatedValue;
5. Customizing @Bean Definitions
You can use SpEL to define conditional bean initialization.
@Bean
@ConditionalOnExpression("#{environment['app.feature.enabled'] == 'true'}")
public MyFeatureBean myFeatureBean() {
return new MyFeatureBean();
}
