2009년 05월 05일
스프링에서 스캔된 컴포넌트에 외부 Property 값 주입하기
서설
스프링 2.5에 새로 추가된 기능 중 예상 외로 인기 있는 기능이 컴포넌트 스캔이다. Classpath를 따라서 탐색 하다가 정해진 필터링 규칙에 맞는 스프링 빈을 찾아 컨테이너에 등록해주는 기능인데 처음 들었을 때 잘 못 쓰면 독이 되겠다 싶었다. Autowiring은 몰라도 최소한 어떤 빈이 사용되는지는 XML에 등록해 주는 것이 관리 하기 좋지 않겠냐는 생각이었다. 빈 등록까지 자동으로 해버리면 애플리케이션 구성을 추적하기 어려워 유지보수가 곤란할 것이기 때문이다. 결국 나는 서비스 계층 후면은 XML을 사용한 전통적인 빈 설정으로, Web Tier는 빈 스캐닝과 Autowiring을 이용하는 방식으로 용처를 정리해서 사용하고 있다.
하지만 내가 결정권이 없는 여러 프로젝트에서 빈 스캐닝 기능을 사용하는 일이 많은 것이 현실이다. 그리고 절대 저질러서는 안 되는 범죄도 아니고 대부분 그리 복잡한 애플리케이션도 아니니 잘못 되었다고 말할 것도 아니다. 결국 두어 번 이런 상황에서 일을 하게 되었다. (사실 XML로 설정을 한다고 해도 관리가 허술하면 복잡하기는 마찮가지다. 설정 관리자라는 롤이라도 두어야 하는 걸까?)
이런 저런 것 떠나서 빈 스캔 기능을 사용하면 가장 곤란한 것이 특정 값을 빈에 설정할 수 없다는 것이다. 스프링은 단순히 빈 간의 종속성 문제만 해결해줄 뿐 아니라 빈의 초기 상태를 설정할 수도 있다. 그런데 XML이 아닌 방법으로 스프링에 의존하지 않고 POJO의 순수성을 유지한채 특정 값을 설정하는 방법이 마땅치 않다. (적어도 내 지식으로는 그렇다.)
애노테이션 환경에서 Property 값 설정
PropertyInjectionConfigurer는 스프링의 PropertyPlaceholderConfigurer나 PropertyOverrideConfigurer와 비슷한 기능을 한다. 즉, 빈 초기화 단계에서 지정된 Property 파일의 값을 특정 빈의 필드에 넣거나 특정 메소드를 이 값을 가지고 호출한다. 다만 XML 설정이 아닌 애노테이션 방식을 사용한다는 것이 다르다. @Property 애노테이션을 Property 값을 받기 원하는 필드나 메소드에는 달아 놓으면 PropertyInjectionConfigurer가 빈 초기화 단계에 이 애노테이션을 인식해서 원하는 값을 찾아 설정을 해준다.
물론 지금 1.0 M4 상태인 Spring JavaConfig나 1.0 M3 상태인 스프링 3가 정식 발표 된다면 문제가 안 되는 부분일 수 있다. 그러니 스프링 2.5만을 사용하고 JavaConfig를 기다릴 수 없는 (또는 JavaConfig를 사용 안 할) 프로젝트에만 사용하면 될 듯 하다. 그리고 JavaConfig의 @ExternalValue가 맘에 안 드는 사람도 있을 듯 하다.
파일 다운로드
property_injection.tar.gz
소스 파일을 이클립스에서 Java 프로젝트(Spring IDE plugins가 설치되어 있으면 spring project)로 Import해서 열면 바로 사용이 가능하다. 일단 처음에는 테스트가 있으니 작동 유무를 이를 통해서 확인 한다.
기존에 프로젝트 코드 베이스에 포함되어 있던 클래스 하나만 분리해서 만든 프로젝트이니 굳이 jar로 만들어 쓰기 보다는 그냥 사용할 프로젝트의 코드 베이스에 복사해서 패키지를 적절하게 변경한 다음에 사용하는 것이 좋을 듯 하다.
설정
가장 먼저 PropertyInjectionConfigurer를 XML에 등록한다.
<bean class="property_injection.PropertyInjectionConfigurer">
<property name="location" value="property_injection/test.properties"/>
</bean>
location 속성에 설정 값이 등록되어 있는 propertis 파일의 경로를 지정한다. 만약 properties 파일이 여러개라면 이렇게 할 수도 있다.
<bean class="property_injection.PropertyInjectionConfigurer">
<property name="locations">
<list>
<value>classpath:property_injection/test.properties</value>
<value>classpath:property_injection/another.properties</value>
</list>
</property>
</bean>
물론 간단히 직접 Properties 값을 주는 것도 가능하다.
<bean class="property_injection.PropertyInjectionConfigurer">
<property name="properties">
<value>
mail.server=mail.domain.net
mail.sender=admin@domain.net
</value>
</property>
</bean>
설정 방법은 PropertyPlaceholderConfigurer와 같으니 레퍼런스를 참조하도록 한다.
필드에 @Property 사용
일단 PropertyInjectionConfigurer를 등록했으면 Property 값을 지정하고 싶은 필드나 메소드에 @Property 애노테이션을 표기해야 한다. 직접 필드에 값을 지정하도록 할 수 있다.
@Property(name="mail.server")
private String mailServer;
메소드에 @Property 사용
메서드에 @Property를 달아 놓으면 초기화 단계에 해당 메소드를 호출한다. 이 메소드는 매개 변수가 하나 이상이어야 한다.
@Property(name="mail.server")
public void setMailServer(String mailServer) {
this.mailServer = mailServer;
}
필수가 아닌 Property
만약 지정한 Property 값을 찾지 못하면 예외를 발생시키기 때문에 빈 생성을 하지 못하게 된다. Property 값이 있어도 되고 없어도 되는 값이라면 required 속성를 false 값으로 바꾸어 예외 발생 없이 넘어가도록 할 수 있다.
@Property(name="property.name" required=false)
required 속성을 사용할 때에는 기본값을 필드에 지정하는 것이 좋을 것이다.
@Property(name="mail.server" required=false)
private String mailServer = "default.mailserver.com";
스프링 2.5에 새로 추가된 기능 중 예상 외로 인기 있는 기능이 컴포넌트 스캔이다. Classpath를 따라서 탐색 하다가 정해진 필터링 규칙에 맞는 스프링 빈을 찾아 컨테이너에 등록해주는 기능인데 처음 들었을 때 잘 못 쓰면 독이 되겠다 싶었다. Autowiring은 몰라도 최소한 어떤 빈이 사용되는지는 XML에 등록해 주는 것이 관리 하기 좋지 않겠냐는 생각이었다. 빈 등록까지 자동으로 해버리면 애플리케이션 구성을 추적하기 어려워 유지보수가 곤란할 것이기 때문이다. 결국 나는 서비스 계층 후면은 XML을 사용한 전통적인 빈 설정으로, Web Tier는 빈 스캐닝과 Autowiring을 이용하는 방식으로 용처를 정리해서 사용하고 있다.
하지만 내가 결정권이 없는 여러 프로젝트에서 빈 스캐닝 기능을 사용하는 일이 많은 것이 현실이다. 그리고 절대 저질러서는 안 되는 범죄도 아니고 대부분 그리 복잡한 애플리케이션도 아니니 잘못 되었다고 말할 것도 아니다. 결국 두어 번 이런 상황에서 일을 하게 되었다. (사실 XML로 설정을 한다고 해도 관리가 허술하면 복잡하기는 마찮가지다. 설정 관리자라는 롤이라도 두어야 하는 걸까?)
이런 저런 것 떠나서 빈 스캔 기능을 사용하면 가장 곤란한 것이 특정 값을 빈에 설정할 수 없다는 것이다. 스프링은 단순히 빈 간의 종속성 문제만 해결해줄 뿐 아니라 빈의 초기 상태를 설정할 수도 있다. 그런데 XML이 아닌 방법으로 스프링에 의존하지 않고 POJO의 순수성을 유지한채 특정 값을 설정하는 방법이 마땅치 않다. (적어도 내 지식으로는 그렇다.)
애노테이션 환경에서 Property 값 설정
PropertyInjectionConfigurer는 스프링의 PropertyPlaceholderConfigurer나 PropertyOverrideConfigurer와 비슷한 기능을 한다. 즉, 빈 초기화 단계에서 지정된 Property 파일의 값을 특정 빈의 필드에 넣거나 특정 메소드를 이 값을 가지고 호출한다. 다만 XML 설정이 아닌 애노테이션 방식을 사용한다는 것이 다르다. @Property 애노테이션을 Property 값을 받기 원하는 필드나 메소드에는 달아 놓으면 PropertyInjectionConfigurer가 빈 초기화 단계에 이 애노테이션을 인식해서 원하는 값을 찾아 설정을 해준다.
물론 지금 1.0 M4 상태인 Spring JavaConfig나 1.0 M3 상태인 스프링 3가 정식 발표 된다면 문제가 안 되는 부분일 수 있다. 그러니 스프링 2.5만을 사용하고 JavaConfig를 기다릴 수 없는 (또는 JavaConfig를 사용 안 할) 프로젝트에만 사용하면 될 듯 하다. 그리고 JavaConfig의 @ExternalValue가 맘에 안 드는 사람도 있을 듯 하다.
파일 다운로드
property_injection.tar.gz
소스 파일을 이클립스에서 Java 프로젝트(Spring IDE plugins가 설치되어 있으면 spring project)로 Import해서 열면 바로 사용이 가능하다. 일단 처음에는 테스트가 있으니 작동 유무를 이를 통해서 확인 한다.
기존에 프로젝트 코드 베이스에 포함되어 있던 클래스 하나만 분리해서 만든 프로젝트이니 굳이 jar로 만들어 쓰기 보다는 그냥 사용할 프로젝트의 코드 베이스에 복사해서 패키지를 적절하게 변경한 다음에 사용하는 것이 좋을 듯 하다.
설정
가장 먼저 PropertyInjectionConfigurer를 XML에 등록한다.
<bean class="property_injection.PropertyInjectionConfigurer">
<property name="location" value="property_injection/test.properties"/>
</bean>
location 속성에 설정 값이 등록되어 있는 propertis 파일의 경로를 지정한다. 만약 properties 파일이 여러개라면 이렇게 할 수도 있다.
<bean class="property_injection.PropertyInjectionConfigurer">
<property name="locations">
<list>
<value>classpath:property_injection/test.properties</value>
<value>classpath:property_injection/another.properties</value>
</list>
</property>
</bean>
물론 간단히 직접 Properties 값을 주는 것도 가능하다.
<bean class="property_injection.PropertyInjectionConfigurer">
<property name="properties">
<value>
mail.server=mail.domain.net
mail.sender=admin@domain.net
</value>
</property>
</bean>
설정 방법은 PropertyPlaceholderConfigurer와 같으니 레퍼런스를 참조하도록 한다.
필드에 @Property 사용
일단 PropertyInjectionConfigurer를 등록했으면 Property 값을 지정하고 싶은 필드나 메소드에 @Property 애노테이션을 표기해야 한다. 직접 필드에 값을 지정하도록 할 수 있다.
@Property(name="mail.server")
private String mailServer;
메소드에 @Property 사용
메서드에 @Property를 달아 놓으면 초기화 단계에 해당 메소드를 호출한다. 이 메소드는 매개 변수가 하나 이상이어야 한다.
@Property(name="mail.server")
public void setMailServer(String mailServer) {
this.mailServer = mailServer;
}
필수가 아닌 Property
만약 지정한 Property 값을 찾지 못하면 예외를 발생시키기 때문에 빈 생성을 하지 못하게 된다. Property 값이 있어도 되고 없어도 되는 값이라면 required 속성를 false 값으로 바꾸어 예외 발생 없이 넘어가도록 할 수 있다.
@Property(name="property.name" required=false)
required 속성을 사용할 때에는 기본값을 필드에 지정하는 것이 좋을 것이다.
@Property(name="mail.server" required=false)
private String mailServer = "default.mailserver.com";
# by | 2009/05/05 05:09 | 프로그래밍 이야기 | 트랙백 | 덧글(0)
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]