21

I have a JSF web application with Spring and I am trying to figure out a way to reference the JVM arguments from the applicationContext.xml. I am starting the JVM with an environment argument (-Denv=development, for example). I have found and tried a few different approaches including:

<bean id="myBean" class="com.foo.bar.myClass">
  <property name="environment">
    <value>${environment}</value>
  </property>
</bean>

But, when the setter method is invoked in MyClass, the string "${environment}" is passed, instead of "development". I have a work around in place to use System.getProperty(), but it would be nicer, and cleaner, to be able to set these values via Spring. Is there any way to do this?

Edit: What I should have mentioned before is that I am loading properties from my database using a JDBC connection. This seems to add complexity, because when I add a property placeholder to my configuration, the properties loaded from the database are overridden by the property placeholder. I'm not sure if it's order-dependent or something. It's like I can do one or the other, but not both.

Edit: I'm currently loading the properties using the following configuration:

<bean id="myDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
    <property name="jndiName" value="jdbc.mydb.myschema"/> 
</bean>

<bean id="props" class="com.foo.bar.JdbcPropertiesFactoryBean">
    <property name="jdbcTemplate">
        <bean class="org.springframework.jdbc.core.JdbcTemplate">
            <constructor-arg ref="myDataSource" />
        </bean>
    </property>
</bean>

<context:property-placeholder properties-ref="props" />
jinxed
  • 235
  • 1
  • 4
  • 9

6 Answers6

27

You can use Spring EL expressions, then it is #{systemProperties.test} for -Dtest="hallo welt"

In your case it should be:

<bean id="myBean" class="com.foo.bar.myClass">
  <property name="environment">
    <value>#{systemProperties.environment}</value>
  </property>
</bean>

The # instead of $ is no mistake!

$ would refer to place holders, while # refers to beans, and systemProperties is a bean.


May it is only a spelling error, but may it is the cause for your problem: In the example for your command line statement you name the variable env

(-Denv=development, for example...

But in the spring configuration you name it environment. But both must be equals of course!

Ralph
  • 118,862
  • 56
  • 287
  • 383
  • I get the same result using this approach as I do using the approach in my example. The string, "#{systemProperties.environment}" is what gets passed to the setter method. – jinxed Apr 11 '11 at 16:07
  • @jinxed: I think I have found the last problem, there was a spelling mistake. - see my extended answer. – Ralph Apr 12 '11 at 06:53
10

If you register a PropertyPlaceholderConfigurer it will use system properties as a fallback.

For example, add

<context:property-placeholder/>

to your configuration. Then you can use ${environment} in either your XML configuration or in @Value annotations.

sourcedelica
  • 23,940
  • 7
  • 66
  • 74
  • When I add this to the configuration, the properties I load from the database are overridden by this property placeholder. Edited original description. – jinxed Apr 11 '11 at 17:27
  • How are the database properties loaded? Are they part of the PropertyPlaceholderConfigurer configuration? – sourcedelica Apr 11 '11 at 17:45
  • They are loaded via JDBC using the configuration shown in the question (above)... – jinxed Apr 11 '11 at 20:27
  • Sorry, I don't see where how they are loaded? – sourcedelica Apr 11 '11 at 20:36
  • Ok, when you say the properties are overridden by the property placeholder, do you mean the ${environment} property placeholder specifically? Or all properties? How are you referencing the properties that you load from the database? – sourcedelica Apr 11 '11 at 20:44
  • When I add the property placeholder either through `` or through `` the properties I loaded from the database seem to be wiped out. Those properties (DB) are referenced in the Spring config by using EL (`value="${REF_SERVICE.WS_URL}"`) for property values defined for other beans in the config. – jinxed Apr 11 '11 at 20:50
  • I would recommend wiring "props" into another bean just to verify that com.foo.bar.JdbcPropertiesFactoryBean is actually loading the properties correctly. – sourcedelica Apr 11 '11 at 20:55
  • I wired props into another bean and verified that all properties are being loaded correctly. That part is working as designed. – jinxed Apr 11 '11 at 21:51
  • So none of the placeholders (eg. ${xxxx}) are working? What are they resolving to? – sourcedelica Apr 11 '11 at 22:04
  • The placeholders for properties loaded from the db are working properly. The placeholders for JVM args are not working, they do not get resolved. Instead, they are passed as a string to the bean's accessor. For example, if I have `value="${environment}"` in the config, the string `"${environment}"` gets passed to the bean instead of `"development"`. – jinxed Apr 11 '11 at 22:12
  • What happens if you don't pass -Denvironment=development to the JVM and instead you put that value in the DB? – sourcedelica Apr 11 '11 at 23:20
  • Interesting. The next step I would recommend is playing with different values of system-properties-mode, eg, ``. Otherwise it sounds like a bug in Spring. Stepping through the Spring code with a debugger would provide the definitive answer. – sourcedelica Apr 12 '11 at 17:26
  • This should be accepted as proper answer - it allows you to define xxx property in you config file (`xxx=val1`) and adds the possibility to override this value via command line `-Dxxx=val2`. Your code then contains only one - `${xxx}` - reference. To make this work you have to define 2 `` with appropriate `order` attribute. – Petr Újezdský Feb 24 '16 at 14:08
4

You can load a property file based on system property env like this:

   <bean id="applicationProperties"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <property name="ignoreResourceNotFound" value="false" />
      <property name="ignoreUnresolvablePlaceholders" value="true" />
      <property name="searchSystemEnvironment" value="false" />
      <property name="locations">
         <list>
            <value>classpath:myapp-${env:prod}.properties</value>
         </list>
      </property>
   </bean>

If env is not set default it to production otherwise development and testing teams can have their flavor of app by setting -Denv=development or -Denv=testing accordingly.

anubhava
  • 761,203
  • 64
  • 569
  • 643
  • Read the thread again. The properties are being loaded from the DB. The question is, how do I use the JVM arguments elsewhere in the config? – jinxed Apr 11 '11 at 22:05
  • This is what I see in your question: `I am starting the JVM with an environment argument (-Denv=development, for example)` I also noted in your edited question you mentioned that you are reading some properties from DB as well. Is there any restriction that properties can be read from ONLY 1 source? – anubhava Apr 11 '11 at 22:15
  • All properties are loaded from the database. I understand the concept of using PropertyPlaceholderConfigurer to pull in JVM arguments, but when I use the PropertyPlaceholderConfigurer, the DB properties that had been successfully loaded, are now missing. – jinxed Apr 11 '11 at 22:24
1

Use #{systemProperties['env']}. Basically pass the propertyName used in the Java command line as -DpropertyName=value. In this case it was -Denv=development so used env.

Community
  • 1
  • 1
Amit M
  • 56
  • 5
0

Interestingly, Spring has evolved to handled this need more gracefully with PropertySources: http://spring.io/blog/2011/02/15/spring-3-1-m1-unified-property-management/

With a few configurations and perhaps a custom ApplicationInitializer if you are working on a Web app, you can have the property placeholder handle System, Environment, and custom properties. Spring provides PropertySourcesPlaceholderConfigurer which is used when you have in your Spring config. That one will look for properties in your properties files, then System, and then finally Environment.

Chris J
  • 9,164
  • 7
  • 40
  • 39
0

Spring 3.0.7

<context:property-placeholder location="classpath:${env:config-prd.properties}" />

And at runtime set: -Denv=config-dev.properties

If not set "env" will use default "config-prd.properties".

disciolli
  • 1
  • 1