본문 바로가기

SpringFramework Core - I. IoC 컨테이너/8. 컨테이너의 확장가능한 부분들

1.8.2.1. 예시: 클래스명의 대체자 PropertySourcesPlaceholderConfigurer

PropertySourcesPlaceholderConfigurer를 통해, 표준적인 자바 Properties를 사용함으로써 서로 다른 파일에 있는 bean 정의들로부터 프로퍼티 값들을 표면화할 수 있다. 그렇게하면 복잡하지 않게, 또 메인 XML 정의나 컨테이너를 위한 파일들을 수정할 때 따르는 위험성 없이 데이터베이스 URL들이나 비밀번호와 같은 환경 프로퍼티 값들을 커스터마이즈할 수 있는 애플리케이션을 배포할 수 있게 된다. 

 

다음 XML 기반의 설정 메타데이터를 참고하자. DataSource가 placeholder 값으로 정의되었다.

<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <property name="locations" value="classpath:com/something/jdbc.properties" />
</bean>

<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
    <property name="driverClassName" value="${jdbc.driverClassName}" />
    <property name="url"             value="${jdbc.url}" />
    <property name="username"        value="${jdbc.username}" />
    <property name="password"        value="${jdbc.password}" />
</bean>

예시는 외부의 Properties 파일에 설정된 프로퍼티들을 보여준다. 런타임 시에 PropertySourcesPlaceholderConfigurer가 메타데이터에 적용되어 DataSource의 몇몇 값들을 대체한다. 대체될 값들은 ${property-name} 형태의 placeholder들로 특정된다. 이는 Ant와 log4j 그리고 JSP의 EL 스타일을 따른 것이다.

 

실제의 값들은 표준적인 자바 Properties 형식에 맞춰 다른 파일들로부터 넘어온다.

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root

그러므로 ${jdbc.username} 문자열은 런타임 시에 'sa'라는 값으로 대체된다. 그리고 다른 placeholder의 값들도 프로퍼티 파일에서 일치하는 key의 값들로 대체된다. PropertySourcesPlaceholderConfigurer는 대부분의 프로퍼티들과 bean 정의의 속성들을 placeholder로 체크한다. 게다가 placeholder의 접두사, 접미사를 커스터마이즈할 수도 있다. 

 

'context' 네임스페이스가 스프링 2.5에서 소개되면서, 설정 element 전용의 프로퍼티 placeholder를 설정할 수 있게 됐다. location 속성 안에서 콤마로 구분된 하나 이상의 위치들을 리스트로 제공할 수 있다. 다음 예시를 참고하라.

<context:property-placeholder location="classpath:com/something/jdbc.properties" />

PropertySourcesPlaceholderConfigurer는 특정한 Properties 파일만 찾아보지는 않는다. 기본적으로, 특정한 프로퍼티 파일에서 프로퍼티를 찾지 못하면 스프링의 Environment 프로퍼티들과 일반적인 자바의 System 프로퍼티들도 찾아본다.

 

 

  PropertySourcesPlaceholderConfigurer를 클래스명을 대체하는 데에 사용할 수도 있다. 이는 런타임 시에 특정한 구현 클래스를 골라내야하는 경우에 때때로 유용하다. 다음 예시는 그 방법을 보여준다.

<bean class="org.springframework.beans.factory.config.PropertySourcesPlaceholderConfigurer">
    <property name="locations">
        <value>classpath:com/something/strategy.properties</value>
    </property>
    
    <property name="properties">
        <value>custom.strategy.class=com.something.DefaultStrategy</value>
    </property>
</bean>

<bean id="serviceStrategy" class="${custom.strategy.class}" />

만약 클래스가 런타임 시에 유효한 클래스로 채워지지 않으면, bean은 non-lazy-init bean을 위한 ApplicationContext의 preInstantiateSingletons() 단계에서 생성될 때쯤 실패한다.