C-Thinker님의 Repository/DAO, DTO, 그리고 확장성과 퍼포먼스란 글과 거기서 인용된 [MyStory Series] Repository? DAO? 을 읽다가 DAO와 리포지토리를 그냥 뭉뚱그려서 같은 개념(주로 레이어를 가리키는 말)으로 사용하는 것이 눈에 띄였다.

‘리포지토리’는 Eric Evans의 DDD책이 나오고 DDD의 관심이 고조되면서 유행하기 시작해서 요즘엔 DAO를 대신하는 폼나는 용어로 많이 쓰이는 듯 하다. 예전에 많이 쓰던 UserDao 대신 UserRepository라고 사용하기도 하고, 스프링의 데이터 액세스 로직을 담은 빈에 사용하는 스테레오타입 애노테이션도 @Repository다.

그런데, DAO나 리포지토리가 그냥 비슷한, 서로 바꿔서 사용할 수 있는 용어일까.

한국 DDD의 아버지라고 불리는 이터너티님의 DAO와 REPOSITORY 논쟁이라는 날카로운 글을 보면 DAO와 리포지토리는 확연이 구분되는 다른 의미를 가진 용어이다. 물론 나는 이터너티님의 의견에 모두 동의하는 것은 아니지만, 어쨌든 원래 리포지토리라는 말이 정의되고 사용되기 시작한 기원을 따져보자면 이터너티님의 지적이 맞는 듯.

보통 DDD 책에서 리포지토리라는 용어를 처음 접한 경우가 많은데 사실 그보다 먼저 나온 마틴 파울러옹의 P of EAA(Patterns of Enterprise Application Architecture) 책에서 먼저 리포지토리가 소개됐다. P of EAA 내용을 소개한 웹 페이지(http://martinfowler.com/eaaCatalog/repository.html)에서도 그 내용을 볼 수 있다. 이 내용만 잘 살펴보더라도 단순히 데이터 액세스(매핑) 레이어를 리포지토리 레이어라고 부르는 것은 적절하지 않은 것 같은데.  뭐 IT 용어가 반드시 하나의 의미로만 사용될 이유야 없으니 부르고 싶은대로 부르겠다면 뭐 할말은 없지만.

웹 페이지보다 좀 더 자세하게 Repository 내용을 다룬 P of EEA 책의 Repository 항목을 보면 관련 샘플 코드도 나와있으니 관심 있으면 살펴보는 것도 좋을 듯. 재밌는 것은 P of EEA의 참고서적에 DDD가 나온다는 것. 출간은 안됐고 저술중인 것으로 나오는데, Repository 항목을 보면 이 책과 Evans에 관한 언급이 나온다. 웹 페이지에선 아예 책 추천도 하고.

그런데 transparent persistency를 지원하는 하이버와 같은 ORM에선 리포지토리의 구현이 상당히 직관적이기도 하다. 소위 리포지토리/DAO 레이어를 취급 안하는 본격 EJB3/JPA 문화에서는 그래서 다르게 받아들이기도 하는 듯. 전에도 개빈 킹은 하이버 사상으로는 DAO와 리포지토리에 대해서 끝까지 차이점을 모르겠다고 하기도.

레이어를 말할 땐 그냥 데이터 액세스 레이어라고 하는게 나에겐 가장 자연스럽지만, 그냥 DAO 레이어라도 해도 그만. 그래도 리포지토리 레이어라는 말은 글세.

그런데 전에도 비슷한 글을 썼던 것 같기도 한데… 흠. 뭐 어때.

CloudFoundry(그냥 줄여서 클파라고 써야지)는 VMWare가 주도해서 만들고 있는 오픈소스 PaaS다. 요즘 잘 나가는 클라우드 서비스의 하나인데, 그 중에서도 플랫폼을 제공하는 클라우드라고 해서 Platform as a Service라고 하고 PaaS(미국애들은 주로 패스라고 읽고, 나는 그냥 파스라고 한다)라고 줄여서 부른다. 클라우드도 그렇지만 플랫폼이라는 말도 워낙 느슨하게 정의되어서 여기저기다 마구 쓸 수 있는 말이라 플랫폼을 클라우드 스타일의 서비스로 제공한다는 PaaS도 마구 가져다 쓰는 경향이 있다. 그래서 그 중에서 애플리케이션을 배포하고 운영하는 런타임 환경을 제공하는 플랫폼을 다시 구분해서 애플리케이션 플랫폼(AP)라고 하고, 그런 플랫폼을 aPaaS라고 구분해서 말하는 사람도 있다. 클라우드와 PaaS 얘기하자면 끝이 없을 것 같으니 대충 접고.

아무튼, 클파는 오픈소스 프로젝트다. 그래서 원하면 클파 소스를 가져다가 맘대로 사용할 수 있다. 아파치2 라이선스니 수정해서 상용으로 다시 팔아먹어도 되고, 고친 소스를 공개하지 않아도 된다. 나름 참여도 활발하다. 처음부터 특정 언어와 서비스에 종속적이지 않게 설계되었기 때문에, 마음만 먹으면 자신이 사용하는 언어와 런타임환경, 각종 서비스 등을 추가할 수도 있다. 내가 처음봤을 땐 자바(톰캣), 루비(Rails, Sinatra), Node 정도의 런타임에 MySQL, MongoDB, Redis, RabbitMQ 정도의 서비스를 지원하는 구조였는데, 소스가 공개되고 오픈소스로 알려지니 다양한 커뮤니티와 기업에서 언어와 서비스 등을 계속 추가해서 지금은 PHP, Python, Scala(Lift) 등도 들어가고 PostgreSQL, MongoDB, Neo4J와 같은 서비스도 지원하기 시작했다. 각 언어 런타임과 서비스의 확장 모듈을 만들어서 클파 개발팀에 제공하면 일정한 과정을 밟아서 공식 소스에 반영하고, VMWare가 직접 운영하는 cloudfoundry.com이라는 클파 기반의 퍼블릭 PaaS에 올려주기도 한다. 최근에는 Iron Foundry라는 이름으로 닷넷을 지원하도록 확장한 클파도 나왔다.

오픈소스를 가져다 아예 독자적인 상용 서비스를 제공하는 곳(http://appfog.com/)도 있다. 여기서 클파에 php 런타임을 추가했고, 이를 다시 클파 프로젝트에 기증한 것으로 알고 있다. 또, SDS에서는 CAPE(Cloud Application Platform for Enterprises)라는 이름으로 클파 기반의 자체 PaaS 솔루션을 만들고 있다고 한다. 작년에 열린 애니프레임 오픈 세미나에서 발표된 자료(http://www.anyframejava.org/node/1322) 를 보면 PaaS와 클파에 대한 많은 정보를 얻을 수 있다. 최근에 CAPE을 오픈소스로 공개하기로 한 것을 철회한다는 공지가 떴는데, 그렇다는 건 원래 오픈소스로 공개할 계획이 있었나보다. 비공개로 전환한 건 이유가 있겠지만 쫌 아쉽네.

클파 자체에 관한 자료와 정보는 인터넷에 많이 있으니 찾아보면 된다.

클파는 4가지 정도 형태로 사용될 수 있다.

하나는 VMWare가 운영하는 cloundfoundry.com에서 제공하는 퍼블릭 PaaS 서비스다. 기본적으로 무료로 사용해볼 수 있다. 어느 단계가 되면 유료 서비스로도 제공될 것 같다. 과금방법에 대해서 논의가 있었던 것 같은데 어떻게 진행됐나 모르겠네.

다른 하나는 Micro Cloud Foundry라는 이름으로 제공되는 개발자용 클라우드 VM을 사용하는 것이다. 이건 cloudfoundry.com과 거의 유사한 환경을 가진 서버를 VMWare player나 vsphere 등을 통해서 개발 환경에서 손쉽게 클파를 경험해볼 수 있게 만든 것이다. 만약 퍼블릭 클파를 사용할 것이라면, 일단 로컬에 이 마이크로 클파(줄여서 마클파라고 부르는)를 설치하고 일단 여기에 애플리케이션을 배포하고 서비스를 구성해서 충분한 테스트를 한 뒤에 퍼블릭 클파에 배포하면 될 것이다.

PaaS을 만약 기업내부 시스템의 운영에 도입하고 싶다면 어떨까? 가상화 환경이나 기업내 IaaS처럼 애플리케이션의 런타임 환경도 간단히 구성해서 운영하는 데 사용하고 싶다면, 프라이빗한 PaaS를 도입해야 한다. 보통 PaaS는 DB나 메시징 시스템과 같은 서비스도 PaaS안에 두고 사용하도록 하는데, 규모가 큰 엔터프라이즈 서비스를 이미 운영한다면 PaaS에서 기업내 서비스 리소스로 연결하는 브릿징 기능도 필요하다. 이런 기능을 갖춘 PaaS를 프라이빗 PaaS라고 한다. 클파의 경우는 VMWare 주도로 오래전부터 프라이빗 PaaS가 개발되왔다. 작년 vForum에서 발표한 것에 따르면 올해 봄쯤 공식적으로 공개된다고 하는데. 아무튼 모든 클파 개발자들이 이 프로젝트에 매달리는지 요즘 몇달간 오픈소스 클파의 업데이트가 전혀 없다.

지금까지 말한 세가지는 모두 VMWare가 클파 프로젝트를 기반으로 다양한 형태의 서비스와 솔루션을 만든 것이다. 만약 프라이빗 PaaS를 구성한다거나, 독자적인 사용 퍼블릭 PaaS 환경을 구축하고 싶다면 이 때는 클파 프로젝트를 활용해서 독자적인 PaaS를 개발하거나 구성해야 한다. 이미 클파는 상당히 완성도가 높은 제품이기 때문에 이를 활용해서 실전에 사용하는 것도 별 무리는 없을 듯 하다.

얘기가 샜네.. – -;

그동안 클파.com이나 마클파의 사용에만 관심을 가졌는데, 지난 달부터는 클파를 이용해서 나만의 PaaS 환경을 꾸려서 개발할 때도 쓰고 고객에 필요에 맞게 프라이빗 PaaS환경을 구축해주는 데도 사용하려고 마음을 먹고 클파를 들여다 보기 시작했다.

클파 프로젝트는 github(github.com/cloudfoundry)에 모두 올라와 있다.

프로젝트가 여러개인데, 그 중에서 vmc는 클라이언트에서 클파를 관리하고, 앱을 배포하고, 모니터링하는데 사용하는 클라이언트 툴이다. vcap은 VMWare Cloud Application Platform의 약자로, 클파 서버의 핵심이다. vcap-services에는 각 서비스의 gateway와 node가 들어있는데 vcap의 submodule이다. vcap-java는 vcap의 자바버전이 아니고, 스프링 프레임워크 지원기능이다. 클파는 런타임과 서비스외에 프레임워크 모듈이 있는데, 사용 프레임워크에 따라서 부가적인 기능을 제공하게 해줄 수 있다. 자세한 건 스프링소스 블로그에 4개의 시리즈로 연재되어있으니 그거 참고. vcap-java-client는 아마 STS의 클파 모듈에서 사용하는 자바 버전의 클라이언트 모듈인 것 같은데 한번도 안 들여다봐서 확실치는 않다.

아무튼, 이 프로젝트들을 잘 활용하면 나만의 클파, PaaS를 만들 수가 있다.

가장 먼저 해볼 일은 이 소스를 가지고 서버에 클파를 설치하는 것이다. 그리고 나서 서비스도 바꿔보고, 클파 소스도 건드려가며 자기가 원하는 최적의 PaaS환경을 만들면 된다.

그런데 클파가 간단히 설치가 될까? 그렇지 않다. 클파를 설치한다는 말부터 다시 생각해봐야 할 것 같다.

클파랑 가장 비슷한 것을 꼽자면 APM 서비스를 제공하는 웹호스팅인 것 같다. APM이 설치되어있고, ftp로 앱을 올릴 수 있고, 각종 웹기반의 어드민 툴을 이용해서 DB설정도 해주고 그런 것. 물론 클파는 APM보다 100배쯤 더 강력하고 편리하지만.

그럼 APM을 설치하고 싶다는 건 무슨 의밀까? OS까지는 설치됐다 치면, 두가지 방법이 있을 것이다. 하나는 사람들이 만들어 놓은 APM 한방설치 패키지를 이용하는 것이다. 나는 써본적 없지만 그런 패키지를 이용하는 사람들은 주변에 많이 봤다. 인스톨러 하나 돌리면 Apache, PHP, MySQL에 설정 프로그램까지 다 한번에 깔리는 것이다. 가장 편하다. 하지만 내가 아파치의 모듈을 좀 다르게 구성하고 싶거나, PHP 버전을 달리한다거나, MySQL도 다른 걸로 바꾸고 싶다면? 그러면 APM 한방설치 툴보다는, 각각의 서비스를 독립적으로 설치하고 설정을 통해서 이를 손쉽게 사용할 수 있도록 만드는게 낫다. 거기에 APM에 올라가는 앱을 관리하는 편리한 툴이 있으면 그걸 마지막으로 얹으면 원시적인 PaaS가 하나 완성되는 것이다.

클파도 마찬가지다. 만약 한방 설치가 가능한 패키지가 있다면, 또는 아예 설치가 완료된 VM 이미지가 있으면 그걸 올리면 가장 편할 거다. 하지만 그런 패키지는 없다. APM과 비교하면 훨씬 많은 서비스가 필요하고, 그렇기 때문에 OS 종류와 버전도 많이 탄다. 그래서 한방 설치는 힘들다. Ubuntu 11.10에는 apt-get으로 한번에 설치할 수 있는 cloudfoundry-server 패키지가 있긴 하지만, 클파 자체가 옛날 버전이라 최신 VMC랑 연결해서 사용해보면 잘 안 맞는다.

VCAP 프로젝트 페이지(https://github.com/cloudfoundry/vcap)를 열어보면 하단 문서에 install 스크립트를 사용하는 방법이 나와있다. Ubuntu 10.04 64bit 서버 버전이라면 이 인스톨 스크립트로 설치가 가능한 것처럼 되어있지만, 설치할 패키지를 모두 따로 모아두었다 그걸 가져와서 설치하는게 아니라 각각 서비스와 관련 툴을 직접 해당 홈페이지에서 가져와 빌드하는 것도 많이 있기 때문에 시간이 지나면 이런 스크립트로는 한방 설치가 어려워진다. 최근엔 업데이트도 잘 안해줘서 더욱 그렇고. 사실 이 인스톨 스크립트는 그냥 설치에 대한 가이드 정도로 참고해야지, 이걸로 설치해보고 안된다고 클파 꼬졀다고 하는 건, 철지난 APM 한방설치 인스톨러 가져다가 해보고는 설치 안된다고 APM 꼬졌네 하는 거랑 다를바 없다.

결국 제대로 클파를 다뤄보려면 필요한 컴포넌트와 서비스 등을 직접 구성하고, 최종적으로 이를 모두 연결해서 PaaS 서비스를 제공해주는 클파 핵심 컴포넌트를 셋업하고 사용할 줄 알아야 한다.

많은 사람들은 클파가 VMWare의 vSphere에만 깔리는 벤더 종속적인 제품이라고 오해하기도 하는데, 마클파랑 프라이빗 클파라면 모를까 오픈소스 클파는 아니다. 또, VCAP의 설치 스크립트나 안내만 보고 Ubuntu에만 설지된다고 하는 사람도 있는데 역시 잘못된 얘기다. 클파는 인프라 종류와 OS, 버전등에 종속적이지 않다. 실제 사용할 서비스만 제대로 구성해주고 클파가 동작하도록 루비환경만 잘 잡아주면 된다. 클파는 루비로 만들어졌거든.

아무튼, 그래서 지난 한달간 틈틈이 클파를 설치해봤는데, 기본 스크립트를 이용해서 Ubuntu 10.04에도 설치해봤고, Ubuntu 자체 패키지로 11.10에도 설치해봤고, 패키지 없이 직접 필요한 컴포넌트를 구성해가며 Ubuntu 11.10과 CentOS 6.0에도 설치했다. 너무 오래되지 않은 Linux 계열 OS라면 별 문제 없이 설치할 수 있다. OS X에도 당연히 잘 될거고. 조금 손을 보면 윈도 서버에도 가능할 것이라고 본다.

일단 클파를 서버 한대에 설치해서 사용해보고, 그리고 멀티 노드로 확장해보는 것도 재밌을 것이다. 클파는 내부에 여러 서비스 컴포넌트들이 있는데, 실제 앱을 설치하고 관리하는 DEA 같은 경우는 서버를 계속 확장해서 늘릴 수 있다. 당연히 MySQL이나 MongoDB같은 서비스도 별도의 서버에 셋업해도 되고. 클파 아키텍처가 매우 유연하기 때문에 원하는맘큼 손쉽게 확장할 수 있다. 클파 아키텍처에 관해선 http://www.springsource.org/node/3478 에서 잘 설명하고 있으니 이걸 보면 감이 잡힐 거다.

기본적으로 클파 서버 구성에 대한 가이드는 VCAP의 setup폴더에 있는 install과 vcap_setup 두개의 설치 스크립트를 참고하면 되는데, 이 두가지 다 좀 엉망이다. 현재 오픈소스로 공개된 vcap에서는 사용하지도 않는 서비스도 마구 깔고. 이리 저리 중복해서 까는 것도 있고. 아무튼 그대로 다 따라하면 쓸데없는 게 많이 깔린다. 클파를 기본적으로 구동하는데 필요로 하는 핵심만 골라서 설치하면 된다.

내가 구성해본 가장 기본 환경은 java, ruby(rails, sintra), node(0.4) 런타임에 mysql 정도인데, 일단 이정도로 시작하고 mongdo, rabbit, redis, neo4j 정도 붙여나가면서 만져보면 될 듯. staging plugin을 참고해서 django, grails, lift, php 등을 사용하도록 구성해봐도 좋을테고. 어쨌든 자기가 사용할 필요가 있는 서비스와 컴포넌트만 골라서 설치할 수 있으면 된다.

현재 vcap install 스크립트는 php, python도 설치하는데 아직 vcap에 바로 연결되는 것도 아니고, 당장 필요한 게 아니면 설치할 필요없다. 루비도 rvm으로 1.8.7과 1.9.2를 설치하고, 또 apt-get으로도 설치하는데. 그냥 rvm으로 1.9.2만 설치해도 충분하다. 나중에 staging 서비스 올라갈 때 manifests 보고 1.8을 찾는데 필요하지 않으면 그냥 manifests에서 1.8 항목을 지워도 그만.

Linux 서버를 어느 정도 다뤄본 사람이라면 install 스크립트 따라가면서 차근차근 설치해보면 어렵지 않을 것이다. 간혹 예전 버전을 설치한다거나, 앞에서 설치한 걸 또 깐다거나 하는 부분이 있는데 이런 건 상식적으로 생각해보고 생략하면 된다.

bin/vcap 실행 스크립트에서 Run 모듈의 self.services 메소드를 찾아서 서비스 항목을 빼주면 필요없는 gateway, node가 뜨지 않을 것이다. 또 스크립트에 버전이 명시된 것들도 있는데(erlang, redis, ruby 등등) 그냥 최신 버전 써도 아직은 별 문제되는 것을 못 봤다. 기본적으로 설치 스크립트는 Ubuntu 환경에서 돌아가는 것으로 작성되서, CentOS 등에서 설치하려면 필요한 라이브러리를 잘 찾아서 넣어줘야 한다. 빌드하다 에러나면 메시지 잘 보고 관련 패키지를(주로 –devel로 끝나는 라이브러리) 설치해주는 것으로 충분하다.

자기만의 클라우드 PaaS를 만들어서 사용해보고 싶은 사람이 있으면 한번쯤 서버환경을 꾸며 놓고(메모리만 넉넉하면 VMWare에 서버 설치하고 해봐도 될테고) 클파 깔아서 사용해보면 재밌을 것이다.

앞으로는 다양한 종류의 서비스와 런타임을 구성해보고 클파의 각 컴포넌트들이 어떻게 동작하는지 좀 더 연구해볼 생각이다.

혹시 비슷한 관심이 있는 분들이 있다면 작은 모임(클파사용자모임?)을 만들어서 서로 정보도 주고 받으며 교류해봐도 좋겠다.

스프링 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