como ler a variável de ambiente do sistema no Spring applicationContext

116

Como ler a variável de ambiente do sistema no contexto do aplicativo?

Eu quero algo como:

<util:properties id="dbProperties"
        location="classpath:config_DEV/db.properties" />

ou

<util:properties id="dbProperties"
        location="classpath:config_QA/db.properties" />

dependendo do ambiente.

Posso ter algo assim no contexto do meu aplicativo?

<util:properties id="dbProperties"
        location="classpath:config_${systemProperties.env}/db.properties" />

onde o val real é definido com base na VARIÁVEL DO AMBIENTE DO SISTEMA

Estou usando Spring 3.0

Jai
fonte

Respostas:

106

Você está perto: o) Spring 3.0 adiciona Spring Expression Language . Você pode usar

<util:properties id="dbProperties" 
    location="classpath:config_#{systemProperties['env']}/db.properties" />

Combinado com java ... -Denv=QAdeve resolver seu problema.

Observe também um comentário de @yiling:

Para acessar a variável de ambiente do sistema, ou seja, as variáveis ​​de nível do sistema operacional, conforme comentamos, podemos simplesmente usar "systemEnvironment" em vez de "systemProperties" nesse EL. Gostar #{systemEnvironment['ENV_VARIABLE_NAME']}

amra
fonte
o que significa java ... -Denv = QA?
fresh_dev
2
Você define um valor de propriedade do sistema java. Você pode ler esse valor em código comoassert System.getProperty("env") == "QA";
amra de
Acho que esta resposta está incorreta, isso não permite a leitura de variáveis ​​de ambiente do sistema (ou seja, variáveis ​​de nível de sistema operacional definidas com export, etc), permite apenas a leitura de propriedades do sistema Java.
amoe
2
-Dprop = ... define uma propriedade java na linha de comando. Você pode ler esta propriedade via System.getProperty("prop"). Se quiser ler uma propriedade do sistema operacional, use System.getenv("os-env-variable"). Veja javadoc: docs.oracle.com/javase/6/docs/api/java/lang/System.html
amra
22
Para acessar a variável de ambiente do sistema, ou seja, as variáveis ​​de nível do sistema operacional, conforme comentamos, podemos simplesmente usar "systemEnvironment" em vez de "systemProperties" nesse EL. Gosto #{systemEnvironment['ENV_VARIABLE_NAME']}.
Yiling
51

Hoje em dia você pode colocar

@Autowired
private Environment environment;

em seu @Component, @Beanetc. e, em seguida, acesse as propriedades por meio da Environmentclasse:

environment.getProperty("myProp");

Para uma única propriedade em um@Bean

@Value("${my.another.property:123}") // value after ':' is the default
Integer property;

Outra maneira são os @ConfigurationPropertiesfeijões úteis :

@ConfigurationProperties(prefix="my.properties.prefix")
public class MyProperties {
  // value from my.properties.prefix.myProperty will be bound to this variable
  String myProperty;

  // and this will even throw a startup exception if the property is not found
  @javax.validation.constraints.NotNull
  String myRequiredProperty;

  //getters
}

@Component
public class MyOtherBean {
  @Autowired
  MyProperties myProperties;
}

Nota: Apenas lembre-se de reiniciar o eclipse após definir uma nova variável de ambiente

Dariusz
fonte
1
As variáveis ​​env também podem ser acessadas por meio da Environmentinterface?
Nikhil Sahu
@NikhilSahu Sim, eles são. Você os acessa com a mesma chave que faria ao consultar, java.lang.Systempor exemplo, para obter o tipo de sistema operacional que você faria env.getProperty("os.name")supondo que envseja sua instância de org.springframework.core.env.Environment.
Ninetou
1
@Autowired private Environment environment;não funciona para o meu Componentambiente é sempre nulo
a_horse_with_no_name
26

Sim, você pode fazer, <property name="defaultLocale" value="#{ systemProperties['user.region']}"/>por exemplo.

A variável systemProperties é predefinida, consulte 6.4.1 Configuração baseada em XML .

Istao
fonte
8

Em sua definição de bean, certifique-se de incluir "searchSystemEnvironment" e configurá-lo como "true". E se você estiver usando para construir um caminho para um arquivo, especifique-o como um arquivo: /// url.

Por exemplo, se você tiver um arquivo de configuração localizado em

/testapp/config/my.app.config.properties

em seguida, defina uma variável de ambiente como:

MY_ENV_VAR_PATH=/testapp/config

e seu aplicativo pode carregar o arquivo usando uma definição de bean como esta:

por exemplo

<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="searchSystemEnvironment" value="true" />
    <property name="searchContextAttributes" value="true" />
    <property name="contextOverride" value="true" />
    <property name="ignoreResourceNotFound" value="true" />
    <property name="locations">
        <list>
            <value>file:///${MY_ENV_VAR_PATH}/my.app.config.properties</value>
        </list>
    </property>
</bean>
Brad Parks
fonte
8

Usando Spring EL você pode escrever um exemplo como segue

<bean id="myBean" class="path.to.my.BeanClass">
    <!-- can be overridden with -Dtest.target.host=http://whatever.com -->
    <constructor-arg value="#{systemProperties['test.target.host'] ?: 'http://localhost:18888'}"/>
</bean>
Mikus
fonte
5

Para o meu caso de uso, precisei acessar apenas as propriedades do sistema, mas fornecer valores padrão no caso de serem indefinidos.

É assim que se faz:

<bean id="propertyPlaceholderConfigurer"   
    class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="searchSystemEnvironment" value="true" />
</bean>  
<bean id="myBean" class="path.to.my.BeanClass">
    <!-- can be overridden with -Dtest.target.host=http://whatever.com -->
    <constructor-arg value="${test.target.host:http://localhost:18888}"/>
</bean>
eis
fonte
4

Declare o titular do lugar da propriedade da seguinte maneira

<bean id="propertyPlaceholderConfigurer"   
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="locations">
        <list>
            <value>file:///path.to.your.app.config.properties</value>
        </list>
    </property>
</bean>

Então, digamos que você queira ler o System.property("java.io.tmpdir")seu bean Tomcat ou qualquer bean e adicionar o seguinte em seu arquivo de propriedades:

tomcat.tmp.dir=${java.io.tmpdir}
Justin patel
fonte
1

É assim que se faz:

<bean id="systemPrereqs" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" scope="prototype">
             <property name="targetObject" value="#{@systemProperties}" />
             <property name="targetMethod" value="putAll" />
             <property name="arguments">
                   <util:properties>
                       <prop key="deployment.env">dev</prop>
                   </util:properties>
            </property>
    </bean>

Mas lembre-se de que o Spring é carregado primeiro e então carregará este bean MethodInvokingFactoryBean. Portanto, se você está tentando usar isso para o seu caso de teste, certifique-se de usar depende do. Por exemplo, neste caso

Caso você esteja usando para sua classe principal, é melhor definir esta propriedade usando seu pom.xml como

<systemProperty>
    <name>deployment.env</name>
    <value>dev</value>
</systemProperty>
Atit Shah
fonte
1

Você pode mencionar seus atributos de variáveis ​​em um arquivo de propriedades e definir arquivos de propriedades específicos do ambiente, como local.properties, production.propertied etc.

Agora, com base no ambiente, um desses arquivos de propriedade pode ser lido em um dos ouvintes chamados na inicialização, como o ServletContextListener.

O arquivo de propriedades conterá os valores específicos do ambiente para várias chaves.

Amostra de "local.propeties"

db.logsDataSource.url=jdbc:mysql://localhost:3306/logs
db.logsDataSource.username=root
db.logsDataSource.password=root

db.dataSource.url=jdbc:mysql://localhost:3306/main
db.dataSource.username=root
db.dataSource.password=root

Amostra "production.properties"

db.logsDataSource.url=jdbc:mariadb://111.111.111.111:3306/logs
db.logsDataSource.username=admin
db.logsDataSource.password=xyzqer

db.dataSource.url=jdbc:mysql://111.111.111.111:3306/carsinfo
db.dataSource.username=admin
db.dataSource.password=safasf@mn

Para usar esses arquivos de propriedades, você pode usar REsource conforme mencionado abaixo

        PropertyPlaceholderConfigurer configurer = new PropertyPlaceholderConfigurer();
        ResourceLoader resourceLoader = new DefaultResourceLoader();

        Resource resource = resourceLoader.getResource("classpath:"+System.getenv("SERVER_TYPE")+"DB.properties");
        configurer.setLocation(resource);
        configurer.postProcessBeanFactory(beanFactory);

SERVER_TYPE pode ser definido como a variável de ambiente com valores apropriados para o ambiente local e de produção.

Com essas alterações, o appplicationContext.xml terá as seguintes alterações

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
 <property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <property name="url" value="${db.dataSource.url}" />
  <property name="username" value="${db.dataSource.username}" />
  <property name="password" value="${db.dataSource.password}" />

Espero que isto ajude .

Sunil
fonte
1

Obrigado a @Yiling. Essa foi uma dica.

<bean id="propertyConfigurer"
        class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer">

    <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
    <property name="searchSystemEnvironment" value="true" />
    <property name="locations">
        <list>
            <value>file:#{systemEnvironment['FILE_PATH']}/first.properties</value>
            <value>file:#{systemEnvironment['FILE_PATH']}/second.properties</value>
            <value>file:#{systemEnvironment['FILE_PATH']}/third.properties</value>
        </list>
    </property>
</bean>

Depois disso, você deve ter uma variável de ambiente chamada 'FILE_PATH'. Certifique-se de reiniciar seu terminal / IDE após criar essa variável de ambiente.

Jaikrat
fonte