복붙노트

[SPRING] 스프링 3 표현식 언어는 부동산 자리 표시 자와 어떻게 상호 작용합니까?

SPRING

스프링 3 표현식 언어는 부동산 자리 표시 자와 어떻게 상호 작용합니까?

Spring 3에서는 Bean 정의에서 사용할 수있는 새로운 표현 언어 (SpEL)를 도입했습니다. 구문 자체는 상당히 잘 정의되어 있습니다.

확실하지 않은 점은 SpEL이 이전 버전에 이미 있던 속성 자리 표시 자 구문과 상호 작용하는 방법입니다. SpEL은 부동산 플레이스 홀더를 지원합니까? 아니면 두 가지 메커니즘의 구문과 그들이 결합되기를 희망해야합니까?

구체적인 예를 들어 보겠습니다. $ {x.y.z} 속성 구문을 사용하고 싶지만 $ {x.y.z}가 정의되지 않은 경우를 처리하기 위해 elvis 연산자에서 제공하는 "기본값"구문을 추가해야합니다.

성공없이 다음 구문을 시도했다.

첫 번째 것은 나에게 준다.

이것은 SpEL이 이것을 부동산 자리 표시 자라고 인식하지 못한다고 제안합니다.

두 번째 구문은 자리 표시자를 인식하지 못한다는 예외를 throw하므로 자리 표시 자 확인자가 호출되지만 속성이 정의되어 있지 않으므로 예상대로 실패합니다.

문서는 이러한 상호 작용에 대한 언급이 없으므로 그러한 일이 불가능하거나 문서화되지 않았습니다.

누구든지이 일을 할 수 있었습니까?

좋아, 나는 이것을 위해 작고 독립적 인 테스트 케이스를 생각해 냈다. 이 모든 것이 그대로 작동합니다.

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

문제는 $ {xyz}를 해결할 수없는 경우에 기본값을 지정할 수있는 beans 파일의 SpEL 표현식을 제시하는 것입니다.이 기본값은 다른 속성에 외부화되지 않은 표현식의 일부로 지정해야합니다 세트.

해결법

  1. ==============================

    1.SpEL 표현식에서 속성 자리 표시 자에 액세스하려면 다음 구문을 사용할 수 있습니다. # { '$ {x.y.z}'}. Hovewer는 $ {x.y.z}를 해결할 수 없으면 예외를 throw하기 때문에 엘비스 연산자 및 기본값에 대한 문제를 해결할 수 없습니다.

    SpEL 표현식에서 속성 자리 표시 자에 액세스하려면 다음 구문을 사용할 수 있습니다. # { '$ {x.y.z}'}. Hovewer는 $ {x.y.z}를 해결할 수 없으면 예외를 throw하기 때문에 엘비스 연산자 및 기본값에 대한 문제를 해결할 수 없습니다.

    하지만 속성에 대한 기본값을 선언하는 데 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>
    
  2. ==============================

    2.콜론을 놓친 것 같습니다.

    콜론을 놓친 것 같습니다.

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

    3.자리 표시 자에 대한 기본값을 설정하려면 다음을 참조하십시오.

    자리 표시 자에 대한 기본값을 설정하려면 다음을 참조하십시오.

       <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"/>
    
  4. ==============================

    4.$ {myProps.item : defaultValue}는 myProps.item이 없으면 defaultValue를 사용함을 의미합니다. 이것은 속성 자리 표시 자의 기본 동작입니다.

    $ {myProps.item : defaultValue}는 myProps.item이 없으면 defaultValue를 사용함을 의미합니다. 이것은 속성 자리 표시 자의 기본 동작입니다.

    # {defaultValue}는 리터럴 값에 대한 SpEL을 의미합니다.

    따라서 $ {myProps.item : # {defaultValue}}는 myProps.item이 존재하지 않을 때 SpEL의 값을 계산하여 대상 필드에 할당하는 것을 의미합니다.

    예:

    $ {redis.auth : # {null}}은 redis.auth 속성이 존재하지 않을 때 null로 설정 함을 의미합니다.

  5. ==============================

    5.사실 Property-Placeholder는 문제 자체를 해결할 수 있습니다. 나는. 속성 등록 정보를 사용하여 Spring 컨텍스트에서 명시 적으로 기본 설정을 지정할 수 있습니다. 그런 다음 사용해야 할 설정의 위치를 ​​지정하고 localOverride 속성을 true로 설정할 수 있습니다. 이 경우 외부 자원 (location 속성에 지정된)에서 찾을 수있는 모든 속성은 기본 환경 (환경 내에서 명시 적으로 정의 됨)보다 우선합니다.

    사실 Property-Placeholder는 문제 자체를 해결할 수 있습니다. 나는. 속성 등록 정보를 사용하여 Spring 컨텍스트에서 명시 적으로 기본 설정을 지정할 수 있습니다. 그런 다음 사용해야 할 설정의 위치를 ​​지정하고 localOverride 속성을 true로 설정할 수 있습니다. 이 경우 외부 자원 (location 속성에 지정된)에서 찾을 수있는 모든 속성은 기본 환경 (환경 내에서 명시 적으로 정의 됨)보다 우선합니다.

    희망을 도왔습니다.

  6. ==============================

    6.자신의 예제에서 실행하려면이 코드를 추가해야합니다.

    자신의 예제에서 실행하려면이 코드를 추가해야합니다.

    <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가 존재하지 않기 때문에 $ {a.b.c}를 멤버 a와 b의 멤버 c가 NPE가되는 결과로 평가하기 때문에 접근하지 못합니다.

  7. ==============================

    7.당신은 할 수있다:

    당신은 할 수있다:

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

    8.나는 다음을 시도하고 그것은 (꽤 못생긴) 일했다 :

    나는 다음을 시도하고 그것은 (꽤 못생긴) 일했다 :

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

  9. ==============================

    9.Elvis을 사용할 필요가 없습니다. 콜론 뒤에 기본값을 제공하십시오.

    Elvis을 사용할 필요가 없습니다. 콜론 뒤에 기본값을 제공하십시오.

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

    또는

    @Retryable(maxAttemptsExpression = "#{${my.max.attempts:10}}")
    public void myRetryableMethod() {
        // ...
    }
    
  10. from https://stackoverflow.com/questions/2041558/how-does-spring-3-expression-language-interact-with-property-placeholders by cc-by-sa and MIT license