23.2.24 設定預設值
SpEl表示式中支援“a?:b”這樣的語法來設定預設值。其表示如果a不為null時其結果為a,否則就為b。
@Test
public void test24 () {
ExpressionParser parser = new SpelExpressionParser();
Assert.assertTrue(parser.parseExpression("#abc?:123").getValue().equals(123));//變數abc不存在
Assert.assertTrue(parser.parseExpression("1?:123").getValue().equals(1));//數字1不為null
}
23.2.25 安全導航
我們可能經常會使用類似於“a.b.c”這樣的用法,表示a的b屬性的c屬性,但如果a為null或者a的b屬性為null時都會出現空指標。為了避免此種情況發生,我們可以在SpEl表示式中使用安全導航,這樣當a為null或a的b屬性為null時將直接返回null,而不丟擲空指標異常。SpEl表示式中安全導航的語法是將點“.”替換為“?.”,即不使用“a.b.c”,而是使用“a?.b?.c”。
@Test
public void test25 () {
ExpressionParser parser = new SpelExpressionParser();
Assert.assertNull(parser.parseExpression("null?.abc").getValue());
Assert.assertNull(parser.parseExpression("T(System)?.getProperty('abc')?.length()").getValue());//數字1不為null
}
23.2.26 獲取bean物件
在SpEL表示式裡面也可以直接訪問bean物件,前提是指定了一個BeanResolver。BeanResolver是一個介面,其只定義了一個方法resolve,用以通過beanName解析為對應的bean物件並返回,具體定義如下。
public interface BeanResolver {
Object resolve(EvaluationContext context, String beanName) throws AccessException;
}
如果要在SpEL表示式中訪問bean物件,我們需要通過StandardEvaluationContext來設定對應的BeanResolver,同時我們需要在SpEL表示式中以“@beanName”的方式來訪問對應的bean物件。如下是一段示例程式碼,我們在表示式中獲取到了名稱為hello的bean物件,並訪問了其getKey()方法。
@Test
public void test26() {
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext();
context.setBeanResolver(new MyBeanResolver());
//訪問bean名稱為hello的bean物件的getKey()方法。
Object obj = parser.parseExpression("@hello.key").getValue(context);
System.out.println(obj);
}
private static class MyBeanResolver implements BeanResolver {
private static ApplicationContext appContext = new ClassPathXmlApplicationContext("applicationContext.xml");
public Object resolve(EvaluationContext context, String beanName)
throws AccessException {
return appContext.getBean(beanName);
}
}
23.3 SpelParserConfiguration
在構建SpelExpressionParser時我們可以給其傳遞一個SpelParserConfiguration物件以對SpelExpressionParser進行配置。其可以用於指定在遇到List或Array為null時是否自動new一個對應的例項,對應SpelParserConfiguration的第一個構造引數;也可以指定在List或Array中對應索引超出了當前索引的最大值時是否自動進行擴充,對應SpelParserConfiguration的第二個構造引數,更多資訊請參考Spring的API文件。如下示例中我們就使用了SpelParserConfiguration物件,指定了在對應的List或Array為null時自動new一個對應的物件,並且在對應的索引超出了List或Array當前的最大索引時自動對其進行擴充。所以如下示例中在我們第一次訪問User的interests時其為null,之後第二次訪問時,由於指定了將自動new對應的物件並且在索引超出時自動進行擴充,所以將new一個List的例項,對應ArrayList,且在索引5不存在時將自動擴充並進行填值,填值時將對List的元素型別String new 6次。所以對於這種情況我們需要保證List或Array中存放的元素型別存在無參構造方法。
class User {
public List<String> interests;
}
@Test
public void test() {
User user = new User();
SpelParserConfiguration parserConfig = new SpelParserConfiguration(true, true);
ExpressionParser parser = new SpelExpressionParser(parserConfig);
//第一次為null
Assert.assertNull(parser.parseExpression("interests").getValue(user));
//自動new一個List的例項,對應ArrayList,並自動new String()新增6次。
Assert.assertTrue(parser.parseExpression("interests[5]").getValue(user).equals(""));
//size為6
Assert.assertTrue(parser.parseExpression("interests.size()").getValue(user).equals(6));
}
23.4 在bean定義中使用SpEl
在bean定義中使用SpEl表示式的語法是“#{exp}”。exp就是對應的表示式。如下示例中我們定義了一個名為hello的bean,在指定其userDir時我們使用了表示式。
<bean id="hello" class="com.app.Hello">
<property name="userDir" value="#{T(System).getProperty('user.dir')}"/>
</bean>
對於系統屬性而言,在bean定義中使用時有一個內建的變數可以使用叫systemProperties,而且在使用時不需要加“#”,即不需要以“#systemProperties”的形式出現。所以上述示例也可以是如下這樣。
<bean id="hello" class="com.elim.learn.spring.bean.Hello">
<property name="userDir" value="#{systemProperties['user.dir']}"/>
</bean>
23.4.1 引用其它bean的屬性
在進行bean定義時,我們也可以通過表示式引用其它bean定義的屬性。如下示例中我們就在定義id為world的bean的key屬性時通過表示式引用了名為hello的bean的key屬性,即world的key屬性也將被賦予值“abc”。
<bean id="hello" class="com.app.Hello">
<property name="key" value="abc"/>
</bean>
<bean id="world" class="com.app.World">
<property name="key" value="#{hello.key}"/>
</bean>
23.4.2 基於註解配置的使用
在基於註解配置的bean定義中我們也可以使用SpEl表示式進行某些定義。在基於註解配置bean定義時我們可以使用@Value註解定義在方法或屬性上來指定對應的值。此時我們就可以使用對應的表示式,當然不使用表示式也是可以的。如下示例中我們就通過@Value指定了userDir和key的值。其中userDir的值的定義使用了SpEl表示式,而key的值的定義是直接定義的。
public class Hello {
@Value("#{systemProperties['user.dir']}")
private String userDir;
@Value("abc")
private String key;
public String getUserDir() {
return userDir;
}
public void setUserDir(String userDir) {
this.userDir = userDir;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
(注:本文是基於Spring4.1.0所寫)