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' }