Explain Codes LogoExplain Codes Logo

Spring Boot and multiple external configuration files

java
spring-boot
property-management
configuration
Nikita BarsukovbyNikita Barsukov·Aug 8, 2024
TLDR

To reference multiple configuration files, use spring.config.import in your application.properties or application.yml:

properties:

spring.config.import=optional:file:./config/external-config.properties

yaml:

spring: config: import: optional:file:./config/external-config.yaml

Use optional: prefix if file absence is an expected scenario and chain multiple files using commas. Leveraging multiple configs helps simplify dynamic and modular properties management.

Making the most out of Spring Boot configurations

Order up! Consider the sequence of property resolution

In the Spring Boot orchestra, not all instruments play the same tune. The system resolves properties in a particular order, so it's vital to understand which plug gets into which socket:

  1. Devtools global settings, your firstborn child. Home is where the .spring-boot-devtools.properties is.
  2. @TestPropertySource annotations on tests, because who doesn't want bespoke properties served test-first?
  3. @SpringBootTest#properties annotation attribute on tests: Test two for extra confidence.
  4. Command line arguments — no need for introductions.
  5. SPRING_APPLICATION_JSON properties from inline JSON in an environment variable or system property because we all need a bit of JSON in our lives.
  6. ServletConfig init parameters. They're the quiet ones in the corner, but they still matter.
  7. ServletContext init parameters: They've always got your back when it comes to web applications.
  8. java:comp/env JNDI attributes: because Java Naming and Directory Interface needed more acronyms.
  9. Good old Java System properties (System.getProperties()): Reliable as a grandfather clock.
  10. OS environment variables: Like the weather, they're everywhere.
  11. RandomValuePropertySource with properties only in random.*, for when you're feeling lucky.
  12. Profile-specific application properties outside your jar (application-{profile}.properties and YAML variants): because we respect individuality.
  13. Profile-specific application properties inside your jar (application-{profile}.properties and YAML variants): Ditto.
  14. Application properties outside the jar (application.properties and YAML variants): because sometimes, the classics are the best.
  15. Application properties inside the jar (application.properties and YAML variants): again, because classics.
  16. @PropertySource annotations on your @Configuration classes: The property whisperers.
  17. Default properties (SpringApplication.setDefaultProperties): They've got you when you've got nowhere else to go.

Tailored properties for different suits

To apply different configurations for different environments, the spring.profiles.active property is your fashion designer. Outfit your app with the correct profile either statically in your application.properties or more dynamically via command line arguments:

spring.profiles.active=dev

or

java -jar myapp.jar --spring.profiles.active=dev

Flexibility is a virtue

When going the extra mile with external configurations, add a splash of flexibility. Embrace spring.config.location and end the path with /. That little slash tells Spring Boot to treat the location as directory, effectively overlaying custom configs onto your default stage:

spring.config.location=file:/etc/myapp/ # Don't forget the slash! 🥷

Transformers: Property files in disguise

You can use PropertySourcesPlaceholderConfigurer in your configuration class for power-level property management. Manage loading order of property files, control resolution, and impress your friends!

@Bean public static PropertySourcesPlaceholderConfigurer propertiesResolver() { PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer(); pspc.setLocations( new FileSystemResource("external.properties"), // Transformers: Animals in Disguise new ClassPathResource("default.properties") // This one's just a car, but still cool ); pspc.setIgnoreResourceNotFound(true); // 'Cause nobody likes a drama queen return pspc; }

Practical applications and known issues

Decoding property injection

Now, let's inject property values dynamically into fields, akin to a charisma boost for your configs. The @Value annotation can work wonders:

@Component public class ExcitingValues { @Value("${some.external.property:default_value}") // I am inevitable private String dynamicProperty; // dynamicProperty now contains your external property or 'default_value' if not found. Neat, huh? }

Thread with caution

Be wary of a few risks whilst dealing with multiple configurations:

  • Misconfigured property sources leading to unintentional overrides. Akin to accidental photo-bombing, but less fun.
  • Profile activation conflicts may lead to wrong configuration values. Like wearing swimwear to a ski resort.
  • Syntax errors in properties or yml files can lead to silent failures—so always double-check!

You can also launch your app by passing -Dspring.config.location to take charge of property file order manually. Surgeon-like precision!

java -jar myapp.jar -Dspring.config.location=classpath:/default.properties,file:/path/to/custom.properties