Can I define System Properties within Spring Boot configuration files?
Asked Answered
C

5

51

I have a single application.yml configuration file for my Spring Boot app that defines two profiles (as described in the documentation).

When the production profile is enabled, I would like to set the http.maxConnections system property to a custom value, e.g.

spring:
    profiles:
        active: dev
---
spring:
    profiles: dev
---
spring:
    profiles: production
http:
    maxConnections: 15

But this doesn't actually set the system level property; it appears to just create an application-level property. I've verified this through both http://locahost:8080/env and a JMX Console when comparing launching by

java -jar -Dspring.profiles.active=production myapp.jar

versus

java -Dhttp.maxConnections=15 myapp.jar

I suppose I could create a bean that's @Conditional on the "production" profile that programmatically callsSystem.setProperty based on my application.yml-defined property, but is there a simpler way through configuration files alone?

Cussed answered 27/4, 2016 at 16:30 Comment(0)
D
16

I suppose I could create a bean that's @Conditional on the "production" profile that programmatically callsSystem.setProperty based on my application.yml-defined property, but is there a simpler way through configuration files alone?

I think that's your best bet here. Spring Boot does that itself in its LoggingSystem where various logging.* properties are mapped to System properties.

Note that you'll probably want to set the system properties as early as possible, probably as soon as the Environment is prepared. To do so, you can use an ApplicationListener that listens for the ApplicationEnvironmentPreparedEvent. Your ApplicationListener implementation should be registered via an entry in spring.factories.

Digestant answered 27/4, 2016 at 17:6 Comment(0)
G
21

You may try.

@Profile("production")
@Component
public class ProductionPropertySetter {

   @PostConstruct
   public void setProperty() {
      System.setProperty("http.maxConnections", "15");
   }

}
Guttle answered 27/4, 2016 at 16:38 Comment(3)
the problem is, you need to redeploy if you want to change this, otherwise you could just modify it and reboot your appDiscommend
@Discommend yes, that make sense. I believe you can put properties in application-production.yml which will be used in production profile.Guttle
System.setProperty("http.maxConnections", "15");// int is not allowed here :))Bernadettebernadina
D
16

I suppose I could create a bean that's @Conditional on the "production" profile that programmatically callsSystem.setProperty based on my application.yml-defined property, but is there a simpler way through configuration files alone?

I think that's your best bet here. Spring Boot does that itself in its LoggingSystem where various logging.* properties are mapped to System properties.

Note that you'll probably want to set the system properties as early as possible, probably as soon as the Environment is prepared. To do so, you can use an ApplicationListener that listens for the ApplicationEnvironmentPreparedEvent. Your ApplicationListener implementation should be registered via an entry in spring.factories.

Digestant answered 27/4, 2016 at 17:6 Comment(0)
L
3

You can inject the environment into the constructor of the class that specifies the beans. This allows you to write application properties to the system properties before the beans are being created.

@Configuration
public class ApplicationBeans {

   @Autowired
   public ApplicationBeans(Environment environment) {
      // set system properties before the beans are being created.
      String property = "com.application.property";
      System.getProperties().setProperty(property, environment.getProperty(property));
   }

   /**
    * Bean that depends on the system properties
    */
   @Bean
   public SomeBean someBean() {
      return new SomeBean();
   }
}
Laurelaureano answered 5/7, 2017 at 9:36 Comment(0)
S
0

I encountered a similar challenge and struggled to find a dependable method for externalizing System properties using Spring configuration files. While command-line arguments are an option, I'd prefer to avoid that approach in order to consolidate all configuration settings in one place.

You can use the following class in your project:

import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(
        prefix = "system")
@Lazy(
        value = false)
public class SystemPropertiesInjector {

    private static final Logger LOGGER = LoggerFactory.getLogger(SystemPropertiesInjector.class);

    Map<String, String> properties;

    @PostConstruct
    void init() {
        if (properties != null) {

            for (Entry<String, String> property : properties.entrySet()) {
                LOGGER.info("Injecting Property with Name: {} and Value: {} into System Properties",
                        property.getKey(),
                        property.getValue());
                System.setProperty(property.getKey(), property.getValue());
            }
        }
    }

    public Map<String, String> getProperties() {
        return properties;
    }

    public void setProperties(Map<String, String> properties) {
        this.properties = properties;
    }

}

and in the application.properties:

system.properties.propertyName=propertyValue

The component reads all properties from the Spring Context with prefix "system.properties" and puts them into the System#setProperty. You could of-course change the prefix as required.

Sidestroke answered 7/11, 2023 at 10:25 Comment(1)
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.Darill
O
-1

You can also use PropertyPlaceholderConfigurer from org.springframework.beans.factory.config to get handle over your properties file

Oblivion answered 10/7, 2018 at 11:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.