Skip to main navigation Skip to main content Skip to page footer

Spring Core - Properties and Profiles

| Java Spring Boot

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.

  1. 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; }
}
  1. 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., devprod).

  1. 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

  1. Environment Flexibility: Easily switch between environments (e.g., dev, prod).
  2. Separation of Concerns: Keeps configuration separate from code.
  3. 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();
}
Back