Java Spring3表达式语言如何与属性占位符交互?

Java Spring3表达式语言如何与属性占位符交互?,java,spring,spring-el,Java,Spring,Spring El,Spring3引入了一个新的(SpEL),可以在bean定义中使用。语法本身是相当明确的 目前尚不清楚的是,SpEL如何与先前版本中已经存在的属性占位符语法交互。SpEL是否支持属性占位符,还是必须将这两种机制的语法结合起来,并希望它们结合起来 让我举一个具体的例子。我想使用属性语法${x.y.z},但是添加了由提供的“默认值”语法来处理${x.y.z}未定义的情况 我尝试了以下语法,但没有成功: {x.y.z?:'defaultValue'} {${x.y.z}?:'defaultValue

Spring3引入了一个新的(SpEL),可以在bean定义中使用。语法本身是相当明确的

目前尚不清楚的是,SpEL如何与先前版本中已经存在的属性占位符语法交互。SpEL是否支持属性占位符,还是必须将这两种机制的语法结合起来,并希望它们结合起来

让我举一个具体的例子。我想使用属性语法
${x.y.z}
,但是添加了由提供的“默认值”语法来处理
${x.y.z}
未定义的情况

我尝试了以下语法,但没有成功:

  • {x.y.z?:'defaultValue'}
  • {${x.y.z}?:'defaultValue'}
第一个给我

找不到字段或属性“x” 论类型对象 'org.springframework.beans.factory.config.BeanExpressionContext'

这表明SpEL没有将其识别为属性占位符

第二种语法引发异常,表示占位符无法识别,因此正在调用占位符解析程序,但由于未定义属性,因此按预期失败

文档中没有提到这种交互,所以这样的事情要么是不可能的,要么是没有文档记录的

有人做到了吗


好的,我为这一点提出了一个小型的、独立的测试用例。这一切都按原样进行:

首先,bean定义:

<?xml version="1.0" encoding="UTF-8"?>

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

    <context:property-placeholder properties-ref="myProps"/>

    <util:properties id="myProps">
        <prop key="x.y.z">Value A</prop>
    </util:properties>

    <bean id="testBean" class="test.Bean">
            <!-- here is where the magic is required -->
        <property name="value" value="${x.y.z}"/> 

            <!-- I want something like this
        <property name="value" value="${a.b.c}?:'Value B'"/> 
            --> 
    </bean>     
</beans>
最后,测试用例:

package test;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class PlaceholderTest {

    private @Resource Bean testBean;

    @Test
    public void valueCheck() {
        assertThat(testBean.value, is("Value A"));
    }
}

挑战-在bean文件中找到一个SpEL表达式,它允许我在无法解析
${x.y.z}
的情况下指定一个默认值,并且该默认值必须作为表达式的一部分指定,而不是在另一个属性集中外部化。

您似乎错过了冒号:

#{ ${x.y.z} ?: 'defaultValue' }

要从SpEL表达式访问属性占位符,可以使用以下语法:
{'${x.y.z}}
。Hovewer,它无法解决elvis运算符和默认值的问题,因为当无法解决
${x.y.z}
时,它会引发异常

但您不需要SpEL为属性声明默认值:

<context:property-placeholder location="..." properties-ref="defaultValues"/>

<bean id = "defaultValues" class = "org.springframework.beans.factory.config.PropertiesFactoryBean">
    <property name="properties">
        <props>
            <prop key="x.y.z">ZZZ</prop>
        </props>
    </property>
</bean>

<bean ...>
    <property name = "..." value = "${x.y.z}" />
</bean>

ZZZ

实际上,属性占位符本身可以解决您的问题。 也就是说,您可以使用property
properties
在Spring上下文中明确指定默认设置。然后,您可以指定应该使用的设置的位置,并将属性
localOverride
设置为
true
。 在这种情况下,将在外部资源中找到的所有属性(在
location
property中指定)将覆盖默认属性(在上下文中明确定义)


希望我能帮上忙。

您需要添加此选项以使其在示例中运行

<bean id="testBean" class="elvis.Bean">
        <!-- here is where the magic is required
    <property name="value" value="${x.y.z}"/>
    -->

        <!-- I want something like this -->
    <property name="value" value="#{myProps.get('a.b.c')?:'Value B'}"/>

</bean>


您的方法不起作用,因为Spring试图用成员
b
和成员
c
对对象
a
求值
${a.b.c}
,这会导致NPE,因为
a
不存在


#{myProps.getProperty('x.y.z')?:'Value B'}

如果您只想设置占位符的默认值,请参阅:


如果要测试与SpEL和占位符之间的交互,请使用以下命令:

   <!-- set value "77-AA-BB-CC-88" when property "x.y.z" not exist -->
   <property name="value" value="77-#{'AA-${x.y.z:BB}-CC'}-88"/>

${myProps.item:defaultValue}
表示当
myProps.item
不存在时,使用
defaultValue
。这是属性占位符的默认行为

#{defaultValue}
表示文本值的SpEL

因此,
${myProps.item:#{defaultValue}}
表示当
myProps.item
不存在时,计算SpEL的值,并将其分配给目标字段

例如:

${redis.auth:#{null}
表示当
redis.auth
属性不存在时,将其设置为
null

您可以:

<bean id="testBean" class="test.Bean">
        <!-- if 'a.b.c' not found, then value="Value B" --->
       <property name="value" value="${a.b.c:Value B}"/> 
</bean>     

。。。
...

   <!-- if 'a.b.c' not found , but 'a.b' found ,then value=${a.b}
      if 'a.b' also not found , then value="a"     
    -->
       <property name="value" value="#{  '${a.b.c:}'  ?: '${a.b:a}' }"/> 
   ...

...

无需使用Elvis,只需在冒号后提供默认值

@Value("${my.connection.timeout:5000}")
private int myTimeoutMillis;


相关:你把表达放在哪里?在代码中,或者在您的xml/@Value/等中。在bean定义xml中,例如,
不确定它是否正确,但是-您尝试过Value=而不是ref=?我没有尝试过,没有,但我尝试解析的是一个bean引用,而不是一个值
ref=“${x.y.z}”
适用于Spring2.5.Urgh,你说得对。。。编辑了我的问题。。它没有修复它,但至少现在我得到了一个更有用的异常…感谢您的建议,但我需要能够使用已经在上下文中的现有属性占位符配置器,我真的无法处理它。此外,我需要能够在线指定默认值,而不是将其外部化。您好,虽然这可能很好地回答了这个问题,但请注意,其他用户可能没有您那么了解。你为什么不加一点解释,解释一下这段代码的工作原理呢?谢谢
 ...
 <!-- if 'a.b.c' not found , but 'a.b' found ,then value=${a.b}
      if 'a.b' also not found , then value="a"     
 -->
 <property name="value" value="${a.b.c:${a.b:a}"/> 
 ...
   <!-- if 'a.b.c' not found , but 'a.b' found ,then value=${a.b}
      if 'a.b' also not found , then value="a"     
    -->
       <property name="value" value="#{  '${a.b.c:}'  ?: '${a.b:a}' }"/> 
   ...
@Value("${my.connection.timeout:5000}")
private int myTimeoutMillis;
@Retryable(maxAttemptsExpression = "#{${my.max.attempts:10}}")
public void myRetryableMethod() {
    // ...
}