package com.example;
public class PlainBean {
private int value;
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans default-autowire="byName"
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer" />
<bean class="com.example.PlainBean" p:value="${value:10}" scope="prototype" />
</beans>
@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "ctx.xml")
public class PlainBeanTest {
@Autowired
private ApplicationContext ctx;
@Test
public void test() {
assertEquals(10, ctx.getBean(PlainBean.class).getValue()); // default value
((ConfigurableEnvironment) ctx.getEnvironment()).getPropertySources()
.addFirst(new MapPropertySource("overriden", Collections.singletonMap("value", "12")));
assertEquals(12, ctx.getBean(PlainBean.class).getValue()); // test failed
}
}
But test will pass if using @Value("${value:10}") instead of p:value="${value:10}" , here is test project ps.zip
Comment From: sbrannen
Thanks for raising the issue.
Your analysis is correct: placeholder values in XML are evaluated only once.
This is by design.
Consequently, we are labeling this issue as a documentation issue to improve the documentation for such scenarios.
Comment From: quaff
It's weird that not keep consistency between xml and annotation, is there any workaround to fix this? I'm using spring-batch and configure job in xml, migration is hard and risky, but changing job behavior at runtime is quite desired.
Comment From: jhoeller
It's rather the other way round: ${...} placeholders are fundamentally static, meant to be resolved once-only ever since they have been introduced in the XML bean definition format (where they get resolved in a dedicated metadata post-process step on startup).
@Value supports such placeholders as well but in the course of annotation values where it falls back to on-demand resolution which effectively results in later resolution than with XML. This is technically not consistent with XML indeed (unavoidably since there is no metadata post-process step for annotation-contained values), however, those placeholders are not meant to change anyway, so the effect should not matter per the original design of such placeholders.
Note that #{...} expressions are dynamic by design and always evaluated on-demand - in XML and annotation values. For values that are expected to change at runtime, that's the recommended approach.
Comment From: quaff
Thanks for elaboration. I found only systemProperties are predefined, please guide me how to refer Environment in spel, such as #{env.getProperty('parts','10')}
UPDATED: I found #{@environment.getProperty('parts','10')} works.
UPDATED: #{environment['parts']?:10} is much better.
Comment From: sbrannen
UPDATED:
#{environment['parts']?:10}is much better.
Yes, that would be the recommended approach to dynamically accessing an environment variable with a default, fallback value.
I'm using spring-batch and configure job in xml, migration is hard and risky, but changing job behavior at runtime is quite desired.
Have you considered using Spring Batch's step scope and/or accessing job parameters via a SpEL expression? Perhaps @mminella can provide further insight here.
Comment From: quaff
UPDATED:
#{environment['parts']?:10}is much better.Yes, that would be the recommended approach to dynamically accessing an environment variable with a default, fallback value.
I'm using spring-batch and configure job in xml, migration is hard and risky, but changing job behavior at runtime is quite desired.
Have you considered using Spring Batch's step scope and/or accessing job parameters via a SpEL expression? Perhaps @mminella can provide further insight here.
Thanks, my puzzle is resolved by #{environment['parts']?:10} and step scope.