스프링 3.1에 도입된 런타임 환경 추상화는 프로파일과 프로퍼티 소스로 구성되어있다. 스프링 설정 파일 외부에 설정용 프로퍼티 값을 두고 관리하는 방법을 사용하려면 프로퍼티 파일(.proerties, .xml)에 값을 넣고 XML에서 ${} 프로퍼티 치환자를 사용하거나 SpEL을 이용해서 <util:properties/>로 정의된 프로퍼티 빈의 값을 끌어오는 방법뿐이었다. 참. 스프링이 ApplicationContext나 BeanFactory처럼 기본으로 @Resource 해주는 systemProperties와 systemEnvironment 빈을 이용하는 방법도 있긴하다. 아참. 웹이라면 컨트롤러 등에서 서블릿 컨텍스트를 가져와서 애트리뷰트나 컨텍스트 파라미터를 읽어도 되겠지. 아차차. <jee:jndi-lookup>으로 JNDI에 설정해둔 값을 가져오는 방법도 가능하게다. 이런. 빈 초기화 하는 즈음에 DB에 넣어둔 프로퍼티 값을 읽거나 RestTemplate으로 다른 서버에서 끌어오는 방법도 가능하겠네.

애플리케이션의 구성 정보를 담은 XML설정파일 말고 주로 런타임 환경과 관련이 있는 속성은 이렇게 다양한 위치에 넣어두고 다양한 방법으로 가져와서 사용할 수 있다. 그런데 이 모든 방법이 대부분 “키와 값의 쌍으로 이루어진 애플리케이션 외부에 정의된 프로퍼티 값을 가져온다”는 공동점이 있으니 추상화를 하면 좋겠다.

그래서 스프링 3.1은 앞에서 말한 다양한 방법(환경변수, 시스템 프로퍼티, JNDI, 서블릿 컨텍스트 파라미터 , 서블릿 콘픽 파라미터, DB나 서버에서 끌어오기 같은 기타 등등)으로 정의된 프로퍼티를 ProperySource라는 개념으로 추상화하고, 이를 PropertyResolver에서 일관된 방법으로 가져올 수 있도록 만들었는데, 환경 추상화 API인 Environment가 바로 이 PropertyResolver의 서브 인터페이스다.

스프링은 고맙게도 프로퍼티 소스로 추상화 했다고 옛정을 버리지는 않았다. 원한다면 이전에 쓰던 placeholder configurer를 그대로 사용할 수 있다. <context:property-placeholder>와 ${}를 그대로 사용할 수 있다는 뜻이다. 대신 내부에선 프로퍼티 소스 추상화를 이용해 통합된 프로퍼티 정보에 접근하는 방법을 사용하도록 변경됐다.

자세한 내용은 올 봄에 나올지도(-_-;;) 모르는 토스3 개정판에서…

그런데 얼마전에 권남님의 http://kwon37xi.egloos.com/4665590 를 읽어보니

properties-placeholder는 부모 자식 관계에 있는 Application Context XML 설정파일들의 경우에도 동일한 properties 파일임에도 모든 Bean 설정 파일에 property-placeholder를 명시해줘야 하는 문제가 있다.

는 얘기가 나온다. 그래서 빈으로 프로퍼티를 정의하고 SpEL로 끌어오는 방법을 추천한다는.

부모-자식 관계의 컨텍스트 구조는 웹 환경에서 루트와 서블릿 컨텍스트가 분리되는 경우가 대표적인데, 루트에 <context:property-placeholder>를 넣어도 서블릿 컨텍스트의 ${}에는 안 먹는다는 얘기인 것 같다. 당연하다. 왜냐하면 기존 <c:pp>는 빈 팩토리의 ${}등이 들어있는 메타 정보(프로퍼티 값)를 가공하는 방식이다. pull이 아니라 push개념인 셈인데, 루트에 정의된 <c:pp>에서 아직 만들어지지도 않은 서블릿 컨텍스트의 메터 정보를 가공한다는 것은 불가능하기 때문이다. 반면에 SpEL은 다른 빈의 값을 끌어오는 pull 방식이라 컨텍스트 생성 시점에 이미 루트 컨텍스트를 부모 컨텍스트로 주입받은 서블릿 컨텍스트 입장에서 루트 컨텍스트의 빈으로 정의된 프로퍼티의 값을 가져오는 건 간단하다.

물론 하나의 프로퍼티 파일 정보를 루트와 서블릿 컨텍스트 간에 공유하게 하는게 바람직한지 시비를 걸 수도 있겠지만, 뭐 쓰는 사람 맘이지.

그리고, “모든 Bean 설정 파일에 p-p를”이라는 건 아닌듯 싶다. <import>를 쓰거나 configLocation에 *를 사용해서 한 컨텍스트가 여러개의 빈 설정 파일을 사용하게 하는 경우라면 p-p는 한번만 넣어줘도 된다.

아무튼 3.0은 그랬지만 3.1에선 더 이상 이런 문제가 없다. 3.1에선 런타임 환경 정보를 통해서 다양한 프로퍼티 소스를 하나로 통합해서 가져오게 하는 방식을 사용하기 때문에 개념적으로 pull인 셈이다. 심지어 <context:property-placeholder>를 사용하더라도 그렇다. 3.1 스타일로 @PropertySource를 사용해서 p-p와 분리한다면 말할 것도 없고.

그러니 3.1에선 프로퍼티 파일 하나를 일개 빈으로 설정하는 SpEL방식보다 프로퍼티 소스로 추상화해서 사용하는 방식을 추천하고, ${} 스타일을 원한다면 예전에 한번 설명했던 PropertySourcePlaceholderConfigurer를 사용하면 될 것이다. XML을 사용하지 않는 경우라면 @Value의 ${}보다는 Environment에서 직접 프로퍼티를 읽는 방식을 써도 좋다.

스프링이 기본적으로 제공하는 6가지 프로퍼티 소스(구현 클래스가 아니라 정말 소스)외에 커스톰 프로퍼티 소스를 사용하고 싶으면 ApplicationContextInitializer를 쓰면 되는데 이게 3.1.1에서도 살짝쿵 버그가 있는 것 같아서 조금 주의해야 할 것 같다. 이 얘긴 다음에.

스프링 3.1의 프로파일은 매력적이다. 이 좋은 걸 왜 진작에 안 만들었을까 싶다.

프로파일을 활성화 시키는 방법은 여러가지다. 컨텍스트의 Environment 오브젝트를 가져와 setActiveProfiles() 해주는 방법도 있고, 시스템 프로퍼티 설정, 환경 변수 설정, JVM 커맨드 라인 파라미터 설정 등등.

WAS에 올라가는 웹 앱이 여러개거나 시스템 관리자가 까칠해서 지원을 잘 안하주는 관계로 JVM 레벨의 프로파일 지정이 곤란하다면 web.xml에 넣는 방법도 있는데, 이 때 servlet context parameter와 servlet init. parameter 두가지가 다 가능하다.

그런데 주의할 점이 있다.

웹 환경에서 루트 앱 컨텍스트는 <listener>로 등록한 컨텍스트 로더가 담당하고,  앱 컨텍스트 옵션은 서블릿 컨텍스트 파라미터를 지정하는 <context-param>을 사용한다.

DispatcherServlet이 만드는 서블릿 앱 컨텍스트에 관한 설정은 <servlet> 안에 <init-param>을 사용해서 앱 컨텍스트 클래스나 파일 등을 지정할 수 있다.

이렇게 사용하던 습관을 가지고 <context-param>은 루트 앱 컨텍스트용이고, <init-param>은 서블릿 앱 컨텍스트용이라고 막연히 생각하고 있으면 active 프로파일 지정할 때 실수 할 수 있다.

왜냐하면 active 프로파일 설정에서는 <context-param>은 해당 웹 애플리케이션의 모든 앱 컨텍스트에 영향을 주기 때문이다.

<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</context-param>

이렇게 해 놓으면 루트 앱 컨텍스트 뿐 아니라 서블릿 앱 컨텍스트에도 active 프로파일이 dev로 잡힌다.

반면에 <servlet> 아래

<init-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>dev</param-value>
</init-param>

 

이렇게 해 놓으면 이건 루트 앱 컨텍스트의 active 프로파일에는 영향을 주지 않는다.

어떻게 보면 이게 자연스럽게 보인다. 서블릿 컨텍스트(즉 웹 앱)가 범위가 더 크므로 서블릿 컨텍스트의 모든 컨텍스트에 영향을 미치는게 맞다. 반면에 서블릿 레벨의 파라미터는 해당 서블릿의 앱 컨텍스트에만 적용되야지.

문제는 앱 컨텍스트의 조건을 줄 때는 이게 분리된다는 점이다. 같은 파라미터 설정 방식이지만 용도에 따라 적용 범위가 달라진다. 그래서 착각할 수도 있으니 주의할 것.

다른 문제로는 루트 앱 컨텍스에만 active 프로파일을 지정할 방법이 없다. 있을지도 모르겠지만 아직까지 못 찾았다.

 

그런데 프로파일을 하나의 웹 앱 안에서도 다르게 줄 필요가 있을까? 없을 거라고 볼 수는 없겠지. 매우 규모가 큰 앱이라 계층별로 독립적으로 개발하고, DS서블릿도 여러개를 사용하는 경우라면 필요에 따라 각각 다른 active 프로파일을 줄 수 있을 것이다. 물론 프로파일을 전체적으로 통일해서 관리하는 게 바람직하겠지만.

오늘의 결론은…

앱 컨텍스트 설정 결과를 꼭 눈으로 확인해서 기대한 대로 원하는 빈이 구성됐는지 확인하자. 특히 프로파일 같은 거 지정은 착각하면 대박 사고가 날지도. 설정 결과 확인 방법은 여기 저기서 많이 얘기했으므로 안해도 되겠지.

스프링 오덕 말고는 관심없을 것 같은 얘기는 여기서 끝. (뭔말하는지 도통 모르신 분들에게는 죄송. 언젠가 이해되실 겁니다)

스프링 3.1의 새로운 기능 중에서 가장 맘에 들었던 @Enable* 스타일의 설정 확장기법에 대해서 그동안 분석하고 생각해봤던 내용을 지난 1월 말에 오픈 커뮤니티 세미나에서 발표를 했는데, 그 동영상이 공개된 걸 발견했다.

당시 몸 컨디션이 너무 안 좋아서 발표를 포기할까도 생각했었는데, 간신히 약 기운으로 버티며 한 시간 반동안 겨우겨우 발표를 했다. 상태가 안 좋아서 횡설수설했을지도…

아무튼 영상이 올라온 걸 발견했으니 공개한다.  @Enable* 활용기법에 관해서는 이걸로 대충 때우고 말아야지. 몇가지 중요한 얘기를 빼먹은 것 같은데 그건 준비하고 있는 개정판에 넣을 생각이고.

세미나 발표 영상은 http://www.olccenter.or.kr/lec/detail.jsp?lec_idx=209 여기서 보면 된다. 가입하고 수강신청을 해야 볼 수 있는데 어짜피 공짜니까 부담없이.

그런데 여기 올라온 발표자료는 최종 버전이 아니라 빠진 부분도 있고 잘못된 내용도 있다. 발표에 사용한 슬라이드 파일은 여기서 받으면 된다.

발표할 때 썼던 예제 코드는 https://github.com/tobyepril/spring31-enable 여기에서 보면 된다. 간단한 설정으로부터 시작해서 다양한 @Enable을 적용해나가는 과정을 예제로 만들어가며 설명했는데, 각 단계는 프로젝트의 브랜치를 만들어 저장해놨으니 https://github.com/tobyepril/spring31-enable/branches 를 참고하면 각 단계 예제를 쉽게 볼 수 있을 것이다.

@Enable* 얘기는 이쯤에서 그만.

참. 내 앞 시간에 발표했던 기선이의 스프링 3.1 테스트와 MVC Test에 관한 내용도 볼만하다. 그동안 수 많은 강의와 발표를 하다보니 이제는 베테랑이 된 기선이의 여유있는 모습을 볼 수 있다. 막판에 예제가 꼬이면서 당황하는 귀여운 모습은 덤으로.

하나더.

그날 발표 내용을 기선이가 정리해서 블로그에 올린 것을 같이 보면 좋을 듯. @Enable*은 기존 XML 커스톰 태그 방식과 달리 바로 따라해볼만큼 쉽다.

오래전 Inside Spring (5) PropertyPlaceholderConfigurer를 @Bean으로 정의해서는 안되는 이유라는 글을 쓴 적이있다. 나름 흥미로운 분석을 통해서 정리한 재밌는 글이라고 생각했는데 별 반응이 없었다. 굳이 스프링 내에서 어떤 일이 일어나는지, BeanFactoryPostProcessor(BFPP)의 동작원리가 뭔지 이해해야 필요를 못 느껴서였을 수도 있고 PPC를 XML에서 사용하면 그만이지, 당시엔 활용도가 낮았던 @Configuration 클래스 내에서 @Bean으로 정의해서 @Value로 값을 받는데 사용할 필요가 없었기 때문일 수도 있다.

그런데 이제는 No XML이라는 슬로건을 걸친 스프링 3.1이 나와서 자바 코드만으로 XML의 모든 설정을 대체할 수 있을 뿐만 아니라 XML보다 더욱 편리하게 사용할 수 있다는 점을 강조하고 있다. 물론 스프링 3.1이라고 XML을 사용하면 안되는 것은 아니며 @Configuration을 사용할 의무도 없다. 하지만 3.0에서 자바 콘픽을 도입한 이후로 이를 충분히 성숙한 레벨로 올려서 실전에서 본격적으로 사용할 수 있도록 만든 것이 스프링 3.1 변화의 핵심이니 3.1을 사용한다면 한번쯤 XML 없는 스프링 설정에 도전해볼만 하다.

스프링 3.1에서 새롭게 소개된 자바코드 설정용 각종 애노테이션과 기법들은 천천히 얘기하기로 하고(실은 지금 그 내용을 담은 토비의 스프링 3 개정판을 열심히 준비하고 있다) 오늘은 BFPP를 @Bean으로 사용할 수 없었던 문제만 다시 짚어보고 스프링 3.1은 이를 어떻게 해결했는지(해결하기는 했는지?) 살펴보자.

PPC를 @Bean의 정의하면 기대한대로 동작하지 않는 이유에 대해서는 이전 글에서 자세히 설명했다. @Configuration 클래스를 이용한 빈 설정을 가능하게 하는 것도 BFPP이며 프로퍼티 파일의 내용을 가져와 ${..}으로 지정된, 빈 프로퍼티 내의 치환자에 값을 넣어주는 PropertyPlaceholderConfigurer도 BFPP이다. 문제는 @Bean으로 정의된 빈은 @Configuration을 담당하는 ConfigurationClassPostProcessor(CCPP)에 의해서 빈 인스턴스가 만들어지는데, 그렇게 만들어진 BFPP 빈은 이미 빈 인스턴스가 만들어져 사용된 @Configuration 빈의 @Value 프로퍼티 값을 바꿀 수 없기 때문이다.

이 이야기가 어려운 듯 보이지만 사실.. 어렵지 않아요.

BFPP와 BPP(BeanPostProcessor)의 차이점만 이해하면 쉽게 이해할 수 있다. BFPP는 빈의 메타 데이터(클래스는 뭐고 프로퍼티 값의 정의는 뭐고 등등)를 조작하는 후처리기고, BPP는 빈의 인스턴스 값을 조작하는 후처리기다. PPC는 BFPP이므로 메타 데이터만 조작할 수 있다. 하지만 PPC가 @Bean에 의해서 만들어지는 시점에 이미 @Configuration 클래스로 정의된 빈은 메타 데이터 단계가 아니라 인스턴스까지 만들어진 상태다. @Bean 메소드를 실행해서 PPC빈을 만들어야 하니 당연히 이미 @Configuration 인스턴스가 필요할 수 밖에. 결국 PPC가 아무리 메타 데이터에 있는 ${..}을 찾아서 봐꿔봐야. 이미 인스턴스 생성이 끝난 @Configuration 빈의 @Value가 붙은 프로퍼티의 값은 변경할 수가 없다. 빈을 다시 만들지 않을테니까. new XXX() 해서 인스턴스를 만들고 나서 XXX.class 파일을 아무리 조작해봐야 이미 만들어진 인스턴스는 변하지 않는 것과 마찬가지라고 보면 된다.

그렇다면 이를 피할 방법은 뭐가 있을까?

방법은 간단하다. BFPP가 만들어진 후에 @Value가 붙은 @Configuration 클래스가 빈으로 만들어지도록 하면 된다.

가장 쉬운 방법은 BFPP를 @Configuration내의 @Bean이 아닌 XML에 정의하고 이를 @ImportResource로 가져오는 것이다. XML에는 다음과 같이 PPC가 생성되도록 빈을 정의한다. 친절한 스프링 덕에 커스톰 태그 하나면 충분하다.

<context:property-placeholder location="message.properties" />

그리고 이 XML을 @Configuration 클래스에서 @ImportResource로 불러온다.

@Configuration
@ImportResource("context.xml")
public class Config {
    @Value("${name}") String name;

이렇게 해두면 친절한 스프링은 Config 빈을 만들기 전에 XML의 빈들을 먼저 만들고 이때 만들어진 PPC는 Config 빈의 메타 정보에 적용이되서 ${name}을 이용해서 name 프로퍼티 값이 설정이 된다.

또는, 이전 글에서 예로 보였던 것처럼 @Value가 붙은 @Configuration 클래스가 아닌 다른 빈 클래스를 정의해서 거기서 PPC가 만들어지게 하면 된다. PPC를 확장해서 @Component로 정의하는 것도 되고, 또 다른 @Configuration 클래스를 만들어서 그 안에 PPC를 만드는 @Bean을 넣어도 좋다.

@Configuration의 @Value에 ${..}를 적용할 수 있는 방법은 이 두가지 정도.

여기까지는 스프링 3.0의 경우고. 스프링 3.1의 새로운 방법을 살펴보자.

스프링 3.1에선 더이상 PPC를 쓰지 않는다. PropertySource라는 프로퍼티 값을 다루는 새로운 추상화 방식이 등장하면서 이전에 사용되던 다양한 접근방법들을 하나로 통합해버렸다.  이에 대한 자세한 설명은 나중에.

그래서 스프링 3.1에선 PPC 대신 PropertySourcePlaceholderConfigurer(PSPC)가 사용된다. <context:property-placeholder />에서도 PPC 대신 PSPC가 만들어진다. 이 두가지는 사실 차이점이 제법 있는데 일단 제껴두고 BFPP관점에서만 살펴보자.

PSPC도 여전히 BFPP다. 따라서 3.0에서와 마찬가지로 @Value에 ${..}을 적용하기 위해서는 같은 @Configuration 클래스에서 @Bean으로 PSPC를 정의하면 안된다. 물론 앞에서 소개한 두가지 방법을 이용해서 이를 피할 수 있다. 하지만 스프링 3.1은 이 문제를 보다 세련된 방식으로 해결해버렸다. 그래서 이제는 @Value와 PSPC @Bean 메소드가 같은 클래스에 정의해도 된다.

단, 이 PSPC @Bean은 다음과 같이 스태틱 메소드여야 한다.

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

3.0에선 @Bean 메소드는 final 또는 private이어도 안되고, static 이어도 안됐다. 앞에 두개는 CGLib으로 확장할 때 문제가 되기 때문에 안 되는 것이고, static은 @Bean 메소드 호출을 통한 빈 생성과 참조라는 목적에 맞지 않기 때문이다.

반면에 스프링 3.1은 static @Bean 메소드를 특별한 용도에 한해서 허용한다. 바로 BFPP 빈을 정의할 때다.

@Configuration 빈이 생성되기 전에, 즉 메타 데이터 상태로 있을 때 적용되야할 BFPP 빈이 있다면 이를 static 메소드로 정의한다. 스태틱이므로 빈 인스턴스를 만들지 않아도 호출할 수 있다. 스프링은 @Configuration 클래스 내에 @Bean이 붙은 스태틱 메소드가 있으면 이를 먼저 호출해서 빈을 생성해두고, 그 후에 @Configuration 빈을 만든다. 따라서 BFPP @Bean 빈은 @Configuration 클래스에도 영향을 줄 수 있는 것이다.

스태틱 @Bean 메소드는 BFPP 빈의 문제를 해결하기 위해서 사용되도록 의도된 것이므로 BFPP가 아닌 일반 빈을 만들 때는 사용하지 않는 것이 좋다. 스태틱 메소드이므로 다른 @Bean 인스턴스 메소드를 호출할 수도 없고, @Autowired로 DI받은 빈을 참조할 수도 없다. 그래도 억지로 BFPP가 아닌 빈을 스태틱 @Bean으로 정의하면 스프링이 WARN 레벨의 로그로 경고를 때려줄 것이다. 에러가 나지는 않지만 나중에 코드 리뷰하다 쪽팔릴 수 있으니 쓸데없이 사용하지는 말자.

그런데 위에서 정의한 PropertySourcesPlaceholderConfigurer 빈 메소드는 예전에 PPC를 만드는 @Bean 메소드와 다른 점이 있다. 메시지 파일의 location을 지정하지 않는다는 것인데 그 이유는 스프링 3.1의 프로퍼티 체계가 완전히 다르기 때문이다. PSPC는 프로퍼티 정보를 특정 파일이 아니라 Environment로부터 가져온다. 이 얘기를 마저 하려면 너무 길어져서 여기서 그만. 자세한 것은 조만간 나올 토비의 스프링 3 개정판을 참고 하…

오늘은 여기까지.

혹시 이 설명을 듣고 머리가 너무 아프다면, 잠시 머리를 식힐 겸 아웃사이더 님의 node.js 프로그래밍 책을 구해서 보는 것이 좋겠다. 최근 스프링 프레임워크 개발자들이 관심을 가지는 기술의 하나는 node.js다. 작년 VMForum에서 스프링 소스 호주 지부장이자 스프링 시큐리티, ROO를 만든 벤 알렉스는 키노트에서 스프링과 node.js를 함께 사용하는 멋진 예제를 소개하며 스프링의 미래를 전망했다. 스프링 소스가 참여해서 개발되고 있는 PaaS인 CloudFoundry에도 스프링과 함께 node.js 런타임이 지원되고, 스프링과 손쉽게 연동해서 사용할 수 있는 다양한 방법이 제공되고 있다. 스프링 개발자라면 한번쯤 관심을 가져야 할 기술이다. 아웃사이더님의 책은 내가 node.js를 공부(리뷰에 참여한 덕분에 원고를 좀 일찍 받아봤다)하면서 참고하고 있는데 아주 맘에 든다. 뭐, 내가 이 책의 추천사를 썼기 때문에 하는 말은 아니고…

스프링 3.0에서 코어에 통합된 자바콘픽(@Configuration)은 여러모로 매력적이다. 하지만 그게 왜 매력적인지 느끼기는 쉽지 않다.

일반 개발자들이라면 애플리케이션 빈은 @Component로 스캔해서 만들면 그만이다. 트랜잭션, AOP, 유틸 따위의 인프라 빈은 XML의 <namespace:*>을 이용하면 간편하게 등록하고 설정할 수 있다.

반면 <tx:*>나 <aop:*> 등을 자바코드로 빈을 만들어서 등록하라고 하면 막막하다. @Transactional이 적용되게 하려면 <tx:annotation-driven />을 XML에 넣어주기만 하면 되는데, 이걸 @Cofiguration 클래스의 @Bean메소드로 직접 관련된 빈을 만들려면 어떤 빈 클래스를 어떻게 만들고 설정해야 할지 알 수 없기 때문이다. 스프링 소스를 파보기 전에는 파악하기도 불가능하고, 소스를 본다고 해도 스프링 소스중에서도 가장 난해한 NamespaceHandler류와 BeanDefinitionParser는 해석하려면 상당한 노력이 필요하다. 혹시 자신있으면 ConfigBeanDefinitionParser따위를 한번 들여다 보고 어떤 경우+옵션에 어떤 빈이 어떤 설정으로 만들어지는지 파악해보든가.

그래서 임의의 자바코드를 이용한 빈 등록과 설정 방식을 지원하고, 자동 빈 스캔을 이용할 수 있는 3.0에서도 설정용 XML은 반드시 필요했다.

하지만 스프링 3.0에서는 XML의 전용 설정 태그를 대체할 수 있는 @Enable류의 자바콘픽 설정방식이 등장했다. 그래서 XML없이도 간편하고, 타입체크도 쉬우면서, 훨씬 유연한 방법으로 각종 인프라 빈의 등록과 설정이 가능해졌다. 원하면 스프링관련 XML을 모두 제거하는 것도 가능하다.

XML 몇줄 들어가는 것이 무슨 상관이냐, 스키마도 있어서 IDE에서 자동완성과 타입체크도 된는데라고 생각한다면 그냥 XML 써도 그만이겠지만. 새로운 설정방식에 관심이 있다면 @Enable로 대표되는 자바코드 설정 방식에 도전해보는 것도 좋겠다.

XML을 쓸 때 빈의 종류에 따라서 XML파일을 분리해서 사용하는 경우는 흔치 않다. 기껏해야 웹 관련 여부에 따라서 루트 컨텍스트와 웹 컨텍스트 정도를 구분하는 수준이다. 반면에 자바코드를 이용하면 성격에 맞게 각각의 설정을 독립된 @Configuration 클래스에 분리하는 것이 간편하고, 깔끔하게 보일 수 있다.

예를 들면, <tx:*>류에 대응되는 @EnableTransactionManagement가 붙은 클래스라면 관련된 DataSource나 SessionFactory 빈 등만 넣어두면 깔끔하다. 이러면 설정 클래스를 조합해서 재사용하기도 쉬고, 코드도 직관적이고, 테스트할 때도 원하는 설정 클래스만 모아서 돌리면, 애플리케이션 전체 인프라 빈을 다 가동시키지 않아도 되기 때문에 빠른 실행이 가능하다.

@Enable~류의 가장 큰 매력은 단순히 애노테이션 엘리먼트를 통한 설정만 가능한게 아니라, WebMvcConfigurer와 같은 discoverable config. API를 이용해서 좀더 복잡한 설정이 가능하다는 점이다. 대표적인 것이 3.0에서 가장 어정쩡했던 <mvc:*>를 대체할 수 있는 @EnableWebMvc와 WebMvcConfigurer이다. 종류도 많고 설정 방식도 복잡한 DispatcherServlet의 전략을 <mvc:*>로 꾸미면 상당히 지저분한데,  이를 자바코드만으로 편리하게 만들 수 있다.

@Enable~이 가지는 또 다른 매력은, XML 네임스페이스 활용방법이 그랬던 것처럼, 개발자가 프로젝트에 필요한 인프라 빈 또는 앱 빈을 간결한 방식으로 등록, 설정 가능하도록 직접 활용할 수 있다는 점이다. 만들기 까다로운 스키마-전용태그-빈정의파서 등등 방식보다 훨씬 쉽고 편하게 개발가능하다.

프로젝트에 적용한 사내 프레임워크의 기본 설정등을 @Enable 애노테이션과 엘리먼트 값 정도만 가지고 한방에 설정하도록 하는 것도 가능하다. 예를 들어 @EnbaleHibernate 라는 것을 하나 만들어서, database.properties 정보를 활용해서 DataSource를 만들고, SessionFactory도 만들고, 트랜잭션 AOP도 걸고, 기타 관련 빈 등을 한방에 세팅할 수 있도록 만들 수 있다. 몇가지 @Enable~을 조합하는 것만으로 사내 표준 프레임워크의 인프라 빈을 모두 세팅하는 것도 괜찮은 방법일테다. 매번 샘플에 나온 스픠링 XML을 카피카피 해서 조금씩 고쳐쓰다가, 깜빡하고 한줄 잘못 지워서 엉뚱하게 동작하는 따위를 막아줄 수도 있을테고.

다음 번엔 @Enable~등을 어떻게 만들 수 있는지, 스프링 3.1이 제공하고 실제로 적용한 방식이 무엇인지 정리해보자.

그리고 지금은 구상단계긴한데, 1월 2~3째주쯤에 이에 대해서 관심있는 분들과 함께 흥미로운 세미나를 할까도 생각중이다.

© 2017 Toby's Epril Suffusion theme by Sayontan Sinha