XML Properties를 통해 알아본 Spring 3.1 사용자 정의 PropertySource 등록법 프로그래밍

Spring 3.1에 추가된 PropertySource에 @PropertySource 애노테이션으로는 XML Property 파일을 추가할 수 없는 버그가 있다.
@PropertySource에 지정된 리소스를 읽어들이는 코드인 ResourcePropertySource에 버그가 있기 때문이다. 해당 코드를 보면 지정된 리소스를 무조건 *.properties 파일로 간주하고 읽어버린다.

그런데 문제는 나는 *.properties를 매우 싫어한다. 시대착오적인 설정 파일 *.properties를 버리자. 참조.
일단 버그 리포팅은 해 뒀는데 어쨌든 당장 해결책이 필요해서 땜빵을 해봤다.

원리는 간단하다. @Configuration 지정된 자바 설정 코드에서 @PostConstruct로 Environment 객체에 원하는 프라퍼티를 PropertiesPropertySource로 변환하여 추가해주는 방식을 취해보았다. 프라퍼티 소스는 등록 되더라도 PropertySourcesPlaceholderConfigurer는 작동 안 할 줄 알았는데 그것도 잘 작동한다.

@Configuration
public class SpringConfig {

  @Autowired
  private org.springframework.context.ConfigurableApplicationContext applicationContext;

  @Autowired
  private org.springframework.core.io.ResourceLoader resourceLoader;

  @PostConstruct
  public void addXmlProperties() throws Exception {
    addXmlProperties("classpath:my-properties.xml");
    addXmlProperties("classpath:my-properties2.xml");
  }

  private void addXmlProperties(String location) throws IOException,
      InvalidPropertiesFormatException {
    Resource resource = resourceLoader.getResource(location);

    Properties properties = new Properties();
    properties.loadFromXML(resource.getInputStream());
    applicationContext
        .getEnvironment()
        .getPropertySources()
        .addLast(
            new PropertiesPropertySource(
                getNameForResource(resource), properties));
  }

  // from ResourcePropertySource
  private static String getNameForResource(Resource resource) {
    String name = resource.getDescription();
    if (!StringUtils.hasText(name)) {
      name = resource.getClass().getSimpleName() + "@"
          + System.identityHashCode(resource);
    }
    return name;
  }

  @Bean
  public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
  }
}

사실 이걸 시도해 보기 전까지는 웹 애플리케이션에서 원하는 사용자 정의 프라퍼티 소스를 추가하려면 web.xml의 설정에서 contextInitializerClasses 를 지정하고 새로운 ApplicationContextInitializer 구현체를 만들어야 한다고 생각하고 있었다(지금까지 읽은 문서들은 그렇게 설명을 하고 있었다). 이걸 해보고 나서야 일반적인 Spring 설정 프로세스를 통해서도 충분히 가능함을 알았다.

현재로서는 스프링 컨텍스트 단위 테스트 수준에서만 검증한 상태인데, 실제 프로젝트에 적용했을 때 어떻게 될지는 좀 더 살펴봐야 겠다.

그외 다른 항목들은 내 위키의 springframework:propertysource 를 참조하면 된다.

덧글

  • 애너벨리 2013/05/02 14:06 # 삭제

    스프링의 장점 중 하나인 POJO 개발이 가능하다는 점을 생각해봤을 때, 위와 같이 스프링 API 가 노출되는 것이 약간은 꺼려지기 때문에 , 스프링에서 만들어놓은 확장포인트인 ApplicationContextInitializer 를 구현하여 PropertySource를 추가하는 것이 더 낫지 않나 생각해봅니다.. (이건 어디까지나 개인취향일 수도 있겠죠^^;)
    아참.. ApplicationContextInitializer 를 구현하였을 때 스프링테스트컨텍스트에서 지원이 됩니다.
    @ContextConfiguration(initializers = CustomContextIntializer.class)
    이런 식으로 말이죠 ..
  • 권남 2013/05/02 17:48 #

    말씀하신게 더 일리가 있어보입니다.
    참고로 최신버전에서는 xml properties를 읽을 수 있게 되었습니다.
※ 로그인 사용자만 덧글을 남길 수 있습니다.