web-dev-qa-db-ja.com

Spring 3式言語は、プロパティプレースホルダーとどのように相互作用しますか?

Spring 3では、Bean定義で使用できる新しい expression language (SpEL)が導入されました。構文自体はかなり適切に指定されています。

明確ではないのは、SpELが以前のバージョンに既に存在していたプロパティプレースホルダー構文とどのように相互作用するかです。 SpELはプロパティプレースホルダーをサポートしていますか、または両方のメカニズムの構文を組み合わせて、組み合わせることを望んでいますか?

具体例を挙げましょう。プロパティ構文${x.y.z}を使用したいが、${x.y.z}が未定義の場合を処理するために elvis operator によって提供される「デフォルト値」構文を追加したい。

私は成功せずに次の構文を試しました:

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

最初のものは私に与えます

タイプ 'org.springframework.beans.factory.config.BeanExpressionContext'のオブジェクトでフィールドまたはプロパティ 'x'が見つかりません

これは、SpELがこれをプロパティプレースホルダーとして認識しないことを示唆しています。

2番目の構文は、プレースホルダーが認識されないという例外をスローするため、プレースホルダーリゾルバーisが呼び出されますが、プロパティが定義されていないため、期待どおりに失敗します。

ドキュメントはこの相互作用について言及していないため、そのようなことは不可能であるか、文書化されていません。

誰でもこれを行うことができましたか?


わかりました、私はこれのための小さい、自己完結型のテストケースを思いつきました。これはすべてそのまま機能します:

まず、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>

次に、簡単なBeanクラス:

パッケージテスト;

public class Bean {

    String value;

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

そして最後に、テストケース:

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

チャレンジ-${x.y.z}を解決できない場合にデフォルト値を指定できるようにするBeanファイルでSpEL式を考え出すこと、およびこのデフォルトmustを一部として指定する別のプロパティセットで外部化されていない式。

53
skaffman

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>
27
axtavt

コロンを見逃したようです:

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

${myProps.item:defaultValue}は、myProps.itemは存在しません。defaultValueを使用してください。これがプロパティプレースホルダーのデフォルトの動作です。

#{defaultValue}は、リテラル値のSpELを意味します。

そう、${myProps.item:#{defaultValue}}は、myProps.itemが存在しない場合は、SpELの値を計算し、ターゲットフィールドに割り当てます。

例:

${redis.auth:#{null}}は、redis.authプロパティが存在しないため、nullに設定します。

9
smartwjw

プレースホルダーのデフォルト値を設定する場合は、 this を参照してください。

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

これを使用して、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"/>
8
btpka3

サンプル内で実行するには、これを追加する必要があります

<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は${a.b.c}をオブジェクトaと評価し、メンバーbとメンバーcを評価しようとしますが、aが存在しないためNPEになるため、アプローチは機能しません。

3
micfra

実際、Property-Placeholderは問題自体を解決できます。つまりプロパティpropertiesを使用して、Springコンテキストでデフォルト設定を明示的に指定できます。次に、使用する設定の場所を指定し、プロパティlocalOverridetrueに設定します。そのような場合、外部リソース(locationプロパティで指定)で検出されるすべてのプロパティは、デフォルトのプロパティ(コンテキスト内で明示的に定義)をオーバーライドします。

お役に立てば幸いです。

3
Myron

してもいいです:

<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}"/> 
 ...

または...

   <!-- 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}' }"/> 
   ...
1
qxo

Elvisを使用する必要はありません。コロンの後にデフォルトを指定するだけです。

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

または

@Retryable(maxAttemptsExpression = "#{${my.max.attempts:10}}")
public void myRetryableMethod() {
    // ...
}
0

私は次を試してみましたが、うまくいきました(かなりいです):

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

0
Gergely Toth