Spring 3expression式语言如何与属性占位符交互?

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

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

让我举一个具体的例子。 我想使用属性语法${xyz} ,但增加了elvis运算符提供的“默认值”语法来处理${xyz}未定义的情况。

我已经尝试了下面的语法,但没有成功:

  • #{xyz?:'defaultValue'}
  • #{${xyz}?:'defaultValue'}

第一个给我

在'org.springframework.beans.factory.config.BeanExpressionContext'types的对象上找不到字段或属性'x'

这表明SpEL不会将其识别为属性占位符。

第二个语法抛出一个exception,说占位符不被识别,所以占位符parsing器正在被调用,但是由于该属性没有被定义而失败。

文档没有提到这种交互,所以这样的事情是不可能的,或者是没有logging的。

任何人设法做到这一点?


好的,我想出了一个小型的,自包含的testing案例。 这一切都按原样运行:

首先,这个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="xyz">Value A</prop> </util:properties> <bean id="testBean" class="test.Bean"> <!-- here is where the magic is required --> <property name="value" value="${xyz}"/> <!-- I want something like this <property name="value" value="${abc}?:'Value B'"/> --> </bean> </beans> 

那么,琐碎的bean类:

包testing;

 public class Bean { String value; public void setValue(String value) { this.value = value; } } 

最后,testing用例:

 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")); } } 

挑战 – 在beans文件中提出一个SpELexpression式,它允许我们在${xyz}无法parsing的情况下指定一个默认值,这个默认值必须被指定为expression式的一部分,而不是在另一个属性中被外部化组。

要从SpELexpression式访问属性占位符,可以使用以下语法: #{'${xyz}'} 。 Hovewer,它不能解决你的问题与elvis运营商和默认值,因为它会抛出${xyz}无法解决的例外。

但是你不需要SpEL来声明属性的默认值:

 <context:property-placeholder location="..." properties-ref="defaultValues"/> <bean id = "defaultValues" class = "org.springframework.beans.factory.config.PropertiesFactoryBean"> <property name="properties"> <props> <prop key="xyz">ZZZ</prop> </props> </property> </bean> <bean ...> <property name = "..." value = "${xyz}" /> </bean> 

看来你错过了冒号:

 #{ ${xyz} ?: 'defaultValue' } 

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

  <property name="value" value="${xyz:defaultValue}"/> 

如果你想testing与SpEL和占位符之间的交互,使用这个:

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

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

#{defaultValue}表示文字值的SpEL。

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

例:

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

其实Property-Placeholder可以自己解决你的问题。 也就是说,您可以使用属性properties在Spring上下文中明确指定默认设置。 然后,您可以指定应该使用的设置的位置,并将属性localOverride设置为true 。 在这种情况下,将在外部资源中find的所有属性(在location属性中指定)将覆盖默认值(在上下文中明确定义)。

希望我帮助。

你需要添加这个来让它在你的例子中运行

 <bean id="testBean" class="elvis.Bean"> <!-- here is where the magic is required <property name="value" value="${xyz}"/> --> <!-- I want something like this --> <property name="value" value="#{myProps.get('abc')?:'Value B'}"/> </bean> 

你的方法是行不通的,因为Spring试图通过成员c来评估${abc}到一个成员b的对象a ,因为a不存在会导致一个NPE。

你可以:

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

要么

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

要么 …

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

我已经尝试了以下,它的工作(虽然相当丑陋):

#{ myProps.getProperty('xyz')?:'Value B' }