정상혁정상혁

Spring 3.0부터 추가된 SpEL(Spring E-pression Language)를 응용한 사례입니다.

application context 파일 선언만으로 특정 빈의 속성에 서버 이름을 넣으려면 어떻게 해야하냐는 질문을 받았습니다.

질문자는 아래의 bean설정에 "serverName"이라고 지정된 곳에 각각 실행되는 서버마다 다른 이름을 넣고 싶어했습니다.

persistentMessageStore 선언
<bean id="persistentMessageStore" class="org.springframework.integration.jdbc.JdbcMessageStore">
   <property name="region" value="serverName" />
....

</bean>

나름대로의 FactoryBean을 따로 만들거나 JavaConfig을 써도 쉽게 풀리는 문제이지만, SpEL을 활용하는 것이 기존 설정을 가장 적게 바꾸는 방식입니다.

아래와 같이 java.net.InetAddress.getLocalHost를 bean으로 등록합니다.

<bean id="localHost" class="java.net.InetAddress" factory-method="getLocalHost"/>

SPel이 잘 먹는지는 다음와 같이 테스트 할 수 있습니다.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class HostNameTest {
    @Value("#{localHost.hostName}") String hostName;
    @Test
    public void hostNameShouldBePrinted() throws Exception {
        String expectedHostName = InetAddress.getLocalHost().getHostName();
        assertThat(hostName,is(expectedHostName));
        System.out.println(hostName);
    }
}

위의 테스트 코드에서는 @ContextConfiuguration선언 뒤에 Application context 파일 위치를 지정하지 않았으므로, default로 참조되는 같은 패키지 디렉토리의 HostNameTest-context.xml에 'localHost' bean이 선언되어 있어야 겠죠.

제일 처음의 코드1의 bean선언에서도 마찬가지로 #{localHost.hostName} 을 참조할 수 있습니다.

<bean id="persistentMessageStore" class="org.springframework.integration.jdbc.JdbcMessageStore">
   <property name="region" value="#{localHost.hostName}" />
....

</bean>

SpEL을 활용하면 아래와 같이 bean사이의 연결을 더 유연하게 할 수도 있지만, 컴파일타임에 검증되지 않는다는 단점이 있습니다. 이를 보완하려면 오타를 검증할 수 있는 테스트 코드가 있어야 합니다.

다른 방법으로는, JavaConfig를 활용해서 직접 명시적으로 메소드를 호출해서 hostName을 주입해도 됩니다.

@Bean JdbcMessageStore persistentMessageStore(){
    JdbcMessageStore store = new JdbcMessageStore ();
    store.setRegion(localHost.getHostName());
    return store;
}

@Bean public InetAddress localHost() throws UnknownHostException {
    return  InetAddress.getLocalHost();
}