5

I have created a Spring Boot app which uses a legacy library. This legacy library defines a number of Spring Beans in XML. One of which take in a property value as a constructor argument:

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

    <bean id="myBean" class="com.em.MyBean">
        <constructor-arg name="url" value="${my.url}"/>
    </bean>
</beans>

In my Spring Boot app, I have an application.properties which defines this property as follows:

my.url=http://localhost:8080

I use the Maven Spring Boot plugin to run my app locally as follows:

mvn spring-boot:run

And the property value is injected into the bean as expected.

If I try and override the my.url property on the command line like this:

mvn spring-boot:run -Dmy.url=http://www.override.net

The overriden value is not used and instead, the value inside application.properties is used.

According to the Spring Boot docs, values from the command line should be picked up as the first priority: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html. That does not appear to be the case here because if I remove the property from application.properties then the value passed in on the command line is used so it is not a case of the command line value being ignored altogether. It seems like the application.properties value is overriding the command line value.

Does anyone have any ideas as to what is going on?

chrishern
  • 302
  • 2
  • 6
  • 15
  • 3
    I think using -D would pass the property as jvm argument and not spring boot property. have you tried using `--my.url=http://www.override.net`? – Rahul Sharma May 12 '16 at 16:13
  • Could you post your complete version of the XML config? – Ali Dehghani May 12 '16 at 16:35
  • @RahulSharma I've tried that as per Andy's suggestion below and there was no difference. – chrishern May 13 '16 at 09:24
  • @AliDehghani. Do you mean the XML bean config? If so, there's nothing controversial in there but I've edited the question to include the full config. – chrishern May 13 '16 at 09:27
  • just curious, have you tried just doing `--my.url=http://www.override.net` without any `-Drun.arguments=..`? So just `mvn spring-boot:run --my.url=http://www.override.net`. Does it do anything then? – Rahul Sharma May 13 '16 at 09:33
  • @RahulSharma Yep - Maven doesn't like that. Unable to parse command line options: Unrecognized option: --my.url=http://www.override.net – chrishern May 13 '16 at 09:40
  • hi @chrishern, I'm having the exact same issue, if I remove that property from application.properties, the command line parameter will be recogonized. Just trying to figure out why is this weird behaviour happening – Chenhai-胡晨海 Mar 25 '22 at 19:04

5 Answers5

8

Using -D sets a system property. Spring Boot can consume configuration from System properties so, generally speaking, it'll work. However, it won't work if spring-boot:run is forking a separate JVM for your application as the System property will be set on the wrong JVM. As it is not working, I would guess that is what is happening.

You can use -Drun.arguments to pass arguments to the application that's being run, irrespective of whether it's run in a forked JVM. The arguments should be a comma-separated list each prefixed with --. For example, to set my.url:

mvn spring-boot:run -Drun.arguments=--my.url=http://www.override.net

The other possible cause of this problem is that your main method isn't passing the arguments that it receives into the SpringApplication that it creates. You should also check that your main method looks similar to this:

public static void main(String[] args) throws Exception {
    SpringApplication.run(YourApplication.class, args);
}

Note that args is being passed into the call to SpringApplication.run.

Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • I've tried the change to the way in which I'm passing the argument (i.e. to use -Drun.arguments.... and there is no difference. The main method was already passing the arguments into the created app. I have a number of other properties in the application.properties file and I am able to successfully override them all on the command line using -Dproperty.name=value. It looks like it is to do with the fact that this particular property is used in a Spring bean defined in a library which I'm depending on. – chrishern May 13 '16 at 09:30
2

Just adding a typical mistake: The SpringApplication.run method used in the application main class accepts a variable-length argument and won't throw a compile-time warning if you provide no arguments:

public static void main( String[] args )
{
    SpringApplication.run( MyApplication.class, args );
}

It's important to pass the args argument from the main method on to SpringApplication.run. If you don't then no command line arguments will be picked up or take effect.

lars
  • 640
  • 4
  • 10
1
<context:property-placeholder location="classpath:application.properties"/>

Removing the line above (context:property-placeholder) from my beans.xml file resolved this issue. I believe the classpath:application.properties is locking in exactly where to look (preventing overrides).

  • I was having a similar problem with properties from my apps YAML file not being read, and removing the context:property-placeholder element also fixed my issue. Nice catch. – rscarter Jul 17 '18 at 20:38
0

In my case, I had this defined on my property-placeholder:

local-override="true"

So I removed this and it resolved the issues.

James Watkins
  • 4,806
  • 5
  • 32
  • 42
-1

I eventually resolved this by changing the way in which the beans from the legacy library were defined for the Spring Boot application. Rather than using the applicationContext.xml of the legacy application where the beans were defined, I added them to as @Beans in my configuration class. This resolved the issue.

chrishern
  • 302
  • 2
  • 6
  • 15