태그 : spring

DocBook으로 스프링 레퍼런스 같은 문서를 만들어 보자고

스프링을 알고 나서 사용하는 즐거움 외에 부수적인 즐거움 몇 가지가 있는데 그 중 큰  것은 멋진 소스코드와 설계 노하우를 접할 수 있다는 것과 정말 마음에 드는 기술 문서를 알게 되었다는 것 입니다.

지금까지 많은 기술 문서를 접했지만 스프링 레퍼런스는 정말 읽기 쉽고 원하는 내용을 찾기 쉽게 작성되어 있습니다. 무엇보다 점진적인 학습이 가능합니다.

스프링은 전부 다 몰라서 아는 만큼만 써도 유용하게 쓸 수 있는 프레임워크라고 생각합니다. 그 후에 익숙해져서 더 배우게 되면 그만큼 더 활용할 수 있는... 꺼내도 꺼내도 끝이 없는 화수분 같은 프레임워크입니다. 그리고 레퍼런스도 그렇게 작성되어 있습니다.

그래서 앞으로 저도 프로그램을 만들게 되면 스프링 같이 만들고 레퍼런스를 작성할 때에는 스프링 레퍼런스 처럼 작성하고 싶다는 생각을 하고 있습니다.

좌우간 지금까지는 쓸데 없는 얘기였고... (졸려요. =.=) 이번에 KSUG에서 스프링 레퍼런스를 한글로 공동 번역하는 작업을 진행하기로 했습니다. 시간도 없고 영어 실력도 미천하여 별 도움은 못 되겠지만 늘 받아 먹기만 하는 것이 미안하여 (그리고 공부도 좀 할 요량으로) 참가를 하게 되었습니다.

여러 논의 끝에 HTML로 작업하기로 했는데 정작 스프링 배포본의 HTML 파일은 사람이 작성한 것이 아니고 docbook으로 만든 원본문서를 XSL로 변환해서 자동 생성한 것이라서 아주 지저분하더군요. 버스에서 퇴근하면서 노트북으로 번역을 하고 있기 때문에 마우스질이 힘든데 영 작업이 어렵더라고요.

그래서 그냥 docbook으로 작업을 하고 HTML로 변환한 후에 제출하기로 했습니다.

우선 스프링 CVS에서 레퍼런스 소스를 내려 받고 문서를 빌드하는데 필요한 몇가지 파일을 추가했습니다. spring ant 빌드 파일에서 레퍼런스 빌드 부분만 빼서 빌드 파일도 만들었고요.

한글 문제도 있어서 인코딩을 UTF-8로 되도록 약간 수정했습니다. 아직 PDF는 폰트 설정을 안해서 한글이 안 되지만 HTML 변환은 잘 되네요.

혹시 저 처럼 스프링 레퍼런스 같은 문서를 docbook으로 작성하고 싶으신 분들을 위해서 올려 놓습니다.

저는 아마테라스에서 작업하지만 ant 만 설치되어 있다면 vi나 editplus 같은 일반 에디터로 작업하셔도 됩니다.

나중에 PDF 변환도 한글이 되도록해서 다시 올려 놓겠습니다.

spring_reference.zip


by 박성철 | 2008/09/05 02:31 | 프로그래밍 이야기 | 트랙백 | 덧글(0)

Commons Configuration을 사용한 스프링 운영 환경 설정값 지정

스프링 설정 파일과 운영 환경 설정값

Spring framwork의 IoC 컨테이너 XML 설정 파일을 사용하면 애플리케이션을 유연하게 구성할 수 있습니다. 배포 후에도 지역 상황에 맞춰서 컴포넌트를 다른 것으로 바꾼다거나 운영 설정 값을 바꾸거나 하는 일이 무척 쉽지요.  하지만, 이 파일에는 가볍게 다루기에는 너무 중요한 정보들이 들어 있습니다. 사실 객체 생성 로직이 들어 있는 코드라고 볼 수도 있습니다.

중요한 정보를 가진 파일에 환경에 따라서 자주 변경되는 런타임 설정값들은 같이 두는 것은 적당하지 않습니다. 자주 변경할 것 같은 값들을 컨테이너 설정 파일 외부로 빼서 별도 파일로 관리하는 것이 좋겠지요. spring에 이 용도로 제공하는 후처리기가 두 가지 있는데 하나는 PropertyPlaceholderConfigurer이고 또 하나는 PropertyOverrideConfigurer입니다.

PropertyPlaceholderConfigurer는 컨테이너 설정 파일의 빈들을 만들기 전에 설정 파일 중에 있는 임시표기(Placeholder를 우리말로 뭐라고 해야 할지...ㅡ.ㅡ)를 Properties 파일에 등록한 설정값으로 바꿔줍니다. PropertyOverrideConfigurer는 반대로 빈들을 다 만들고 DI까지 다 완료한 이후에 Properties 파일에 지정한 빈 이름과 필드명에 지정된 값들로 덮어씁니다.

전자는 property 이름을 빈의 구현과 관계없이 논리적으로 정할 수 있는 대신 컨테이너 설정 파일의 설정값이 들어가야 할 위치에 property 이름으로 임시표식을 삽입해줘야 합니다. 후자는 컨테이너 설정 파일을 전혀 손대지 않고도 기본으로 지정된 값을 배치된 운영 환경에 맞는 값으로 덮어쓸 수 있습니다. 하지만 property 이름이 빈 이름에 종속됩니다.

제약

이 두 가지 후처리기를 사용하면 운영 환경에 따라 바뀌는 값을 외부로 뺄 수 있지만 여전히 제약이 남아있습니다. 둘 다 외부 설정 파일로 Properties 파일만 사용할 수 있다는 것이지요. Properties 파일로도 큰 문제 없이 설정을 할 수 있지만 이런 요구가 있을 수 있습니다.
  • Poperties 파일 대신 XML 파일을 쓰고 싶다.
  • DB에 들어 있는 설정 값들로 객체를 만들고 싶다.
  • DB와 XML, Properties 파일을 다 쓰고 싶다.
  • JNDI Tree에 설정값을 넣고 싶다.
  • Windows의 ini 파일이나 Mac의 PropertyList 파일을 쓰고 싶다.
저는 인코딩 문제도 있고 읽기도 좋아서 Properties 보다는 XML을 선호합니다. 그리고 몇몇 설정값은 사용자에게 인터페이스를 제공해서 DB의 값을 조작하게 해야 하는 경우가 있습니다.


Apache Commons Configuration

애플리케이션 운영 환경 설정에 제가 주로 사용하는 기술이 Apache commons 프로젝트 중 한 컴포넌트인 Configuration 입니다.  홈페이지에 의하면 Commons Configuration은 일반화된 설정 인터페이스를 제공함으로써 자바 애플리케이션이 다양한 소스에서 설정을 읽을 수 있도록 해준다고 설명하고 있습니다.

열거하고 있는 소스는 다음과 같습니다.
  • Properties 파일
  • XML 문서
  • Windows INI 파일
  • Property list 파일 (plist)
  • JNDI
  • JDBC Datasource
  • System properties
  • Applet parameters
  • Servlet parameters
Commons Configuration은 이렇게 여러 소스에서 설정값을 읽어오는 기능 외에도 복잡한 XML을 효율적으로 다룰 수 있고  Properties 파일도 기본 API보다 훨씬 다양한 기능을 제공하고 있으며 다양한 타입 접근자를 가지고 있고 여러 소스의 설정값을 통합할 수 있습니다. 자세한 것은 사용자 설명서가 잘 되어 있으니 참고하십시오.

CommonConfigurationFactoryBean

Spring modules 프로젝트를 보면 Apache Commons의 여러 컴포넌트들 중 Configuration, Lang, Chain, Validator의 스프링 통합 컴포넌트들이 있습니다. 그중 Configuration 스프링 통합 컴포넌트가 CommonConfigurationFactoryBean 입니다. 이 빈은 아답터의 일종인데 PropertyPlaceholderConfigurer 같이 PropertyResourceConfigurer를 상속한 빈들에 Commons Configuration의 각종 configuration 객체를 붙일 수 있도록 해줍니다.

CommonConfigurationFactoryBean에 하나 이상의 소스에서 설정값을 읽은 Configuration을 등록한 후 PropertyPlaceholderConfigurer나 PropertyOverrideConfigurer의 properties 필드에 대입을 해주면 CommonConfigurationFactoryBean는 등록된 configuration들에 담겨있는 설정값들을 Properties로 변환해서 전달해줍니다.

사실 CommonConfigurationFactoryBean은 내부적으로 Configuration의 CompositeConfiguration를 가지고 있어서 여러 소스의 Configuration을 합 할 수 있습니다.

myconfig.xml이라는 XML 설정 파일을 사용해서 PropertyPlaceholderConfigurer를 등록하는 스프링 설정은 이렇습니다.

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="properties">
            <bean class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
                <property name="configurations">
                    <list>
                        <bean class="org.apache.commons.configuration.XMLConfiguration">
                            <constructor-arg type="java.lang.String">
                                <value>myconfig.xml</value>
                            </constructor-arg>
                        </bean>
                    </list>
                </property>
            </bean>
        </property>
    </bean>   

단순한 설정인데도 좀 복잡하게 나왔습니다.  보시면 PropertyPlaceholderConfigurer와 CommonsConfigurationFactoryBean와 XMLConfiguration 세 가지 객체가 만들어집니다.

PropertyPlaceholderConfigurer는 위에 설명한 것처럼 스프링 설정에 환경 설정값을 넣어주는 후처리기입니다. XMLConfiguration은 생성자에 지정한 XML 파일을 읽어서 설정값을 담은 Commons Configuration의 configuration 객체 중 하나입니다. CommonsConfigurationFactoryBean는 XMLConfiguration을 받아서 설정값을 Properties로 변환한 후 PropertyPlaceholderConfigurer에게 전달하는 역할을 합니다.

기본값과 로컬 설정의 분리

별도 운영 설정 파일을 만들더라도 모든 설정을 해줄 필요 없이 변경이 필요한 한두 설정값만  변경하고 나머지는 기본값이 대응되도록 하는 것이 운영하는데 도움이 됩니다. 다음과 같이 local_config.xml과 default_config.xml을 만들어서 각각 로컬 설정과 기본 설정 값을 넣도록 합니다.

local_config.xml

<config>
<smtp>
  <host>mail.abc.co.kr</smtp_host>
</smtp>
</config>

default_config.xml

<config>
<smtp>
  <host>mail.myhost.co.kr</smtp_host>
  <port>25</port>
</smtp>
</config>

그리고 이 두 파일을 사동하도록 설정합니다.

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="properties">
            <bean class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
                <property name="configurations">
                    <list>
                        <bean class="org.apache.commons.configuration.XMLConfiguration">
                            <constructor-arg type="java.lang.String">
                                <value>local_config.xml</value>
                            </constructor-arg>
                        </bean>
                        <bean class="org.apache.commons.configuration.XMLConfiguration">
                            <constructor-arg type="java.lang.String">
                                <value>default_config.xml</value>
                            </constructor-arg>
                        </bean>
                    </list>
                </property>
            </bean>
        </property>
    </bean>

   <bean id="mailService" class=".....">
        <property name="host" value="${smtp.host}"/>
        <property name="port" value="${smtp.port}"/>
   </bean>

이렇게 local_config.xml을 먼저 등록하고 default_config.xml을 나중에 등록하면 먼저 local_config.xml의 설정값을 먼저 찾고 만약 이 파일에 찾으려는 설정값이 없으면 그다음 configration인 default_config.xml에서 찾는다.

Configuration을 직접 사용

Commons Configuration은 Properties로 변환해서 컨테이너 설정 파일의 설정값을 지정하는 용도 외에도 복잡한 애플리케이션 설정값을 표현하는 능력이 있습니다. 이런 Configuration의 기능을 직접 쓰고 싶은 경우를 위해서 설정을 분리하고 필요한 객체에서 참조할 수 있도록 하면 유용합니다.

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="properties">
            <bean class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean">
               <property name="configurations">
                    <list>
                         <ref bean="configuration"/>
                    </list>
                </property>
            </bean>
        </property>
    </bean>
   
    <bean id="configuration" class="org.apache.commons.configuration.CompositeConfiguration">
        <constructor-arg>
            <list>
                <bean class="org.apache.commons.configuration.XMLConfiguration">
                    <constructor-arg type="java.lang.String">
                        <value>user-config.xml</value>
                    </constructor-arg>
                </bean>
                <bean class="org.apache.commons.configuration.XMLConfiguration">
                    <constructor-arg type="java.lang.String">
                        <value>default-config.xml</value>
                    </constructor-arg>
                </bean>
            </list>
        </constructor-arg>
    </bean>

   <bean id="mailService" class=".....">
        <property name="host" value="${smtp.host}"/>
        <property name="port" value="${smtp.port}"/>
   </bean>

   <bean id="anotherService" class=".....">
        <property name="configuration" ref="configuration"/>
   </bean>

anotherService는 직접 Configuration 객체를 받아서 그 안에 담겨있는 설정값들을 Commons Configuration이 제공하는 다양한 방법으로 읽어서 작동할 때에 참고할 수 있습니다.



by 박성철 | 2008/02/29 15:16 | 프로그래밍 이야기 | 트랙백 | 덧글(5)

자바용 Active Record 기획안

설  연휴 전날 몇몇 회사 동료와 야근을 하려고 식사를 하던 중 그냥 일찍(?) 나가서 얘기나 하다 집에 가기로 의기투합하여 회사를 나왔다. 2차까지 가며 (1차는 별다방, 2차는 덩킨도넛... 꼭 알콜이 있어야 한다는 편견은 버리삼) 이런 저런 얘기를 하던 중 평소 궁금했던 것을 물어봤다.

"자바용 Active Record를 만들면 좋을지 모르겠는데 어떻게 생각해?"

한동안 이 문제로 고민을 해왔다. 이미 iBatis와 Hibernate같은 유명 인사가 있고 이 외에도 수많은 ORM 도구와 추상화 솔루션이 있는 상황에서, 그리고 우리의 완소 JDBCTemplate가 든든하게 뒷받침을 하고 있는데 Active Record를 따로 만드는 것이 의미 있는지 판단이 잘 서지 않았다. 아무리 Dynamic Proxy를 쓴다고 해도 최소한 인터페이스는 일일이 만들어 만들어줘야 하는 자바에서  생산성을 어느 정도 높일 수 있을지도 의문이었고 어떻게 보면 ORM을 사용하면서 도메인을 DB Table과 1:1로 대응하게 하면 그것에 곧 Active Record와 다를 바 없는 것 아닌가 생각되었기 때문이다.

그런데 동료들은 꼭 필요하다며 이런저런 이유를 늘어놓더니 결국 내 마음에 불을 질러 놓았다. 집에 오며 한 시간 넘게 생각을 해보니 대략 윤곽이 떠올라서 간단히 기획안을 적어본다.

배경

왜 Active Record가 필요할까? 솔직히 말하면 내가 필요하기 때문이다. 난 아직도 ORM을 쓰지 않는다. 더 정확히 말하면 도메인 모델링을 하지 않는다. 도메인 객체가 있기는 하지만 DB 구조를 반영해서 만들어진다. 여전히 모델링 단계에서 DB 설계를 먼저 하고 있고 DBMS의 고유 기능을 사용하는데 익숙하며 두꺼운 추상화 레이어를 두는 것에 막연한 두려움을 느끼고 있다.

무엇보다 프로젝트를 하다 보면 필연적으로 프리렌서와 함께 일을 하게 되는데 배우는데 비용이 많이 드는 기술 때문에 프로젝트에 엄청난 피해를 봤던 경험이 너무 많다. 반면에 롤을 세분화 하기에는 프로젝트 규모가 작다. 대부분 개발자 2-5명이 2-3개월 안에 완료해야 한다. 신입사원 교육 비용도 만만하지 않다.

모 은행 개발 프로젝트에 잠시 투입되었었는데 그 은행에서는 DB 추상화 레이어로 ORM과 SQL Mapper를 준비해 두었다고 한다. 권고하는 것은 ORM이지만 ORM으로 개발하도록 요구했더니 개발자들이 진행을 하지 못해서 결국 SQL Mapper를 추가로 제공할 수 밖에 없었고 대부분 어플리케이션이 SQL Mapper를 사용해서 개발이 되었다고 한다. (나는 iBatis와 jdbcTemplate는 개발 비용이 비슷하고 디버깅은 jdbcTemplate이 쉽다고 생각한다. 적절한 Query Object를 사용하면 동적 SQL 문제도 해결된다.)

마틴 파울러는 개발자들이 SQL을 어려워하고 DB보다 객체 다루기를 더 쉽게 생각하고 있다면서 Domain model과 ORM을 추천하지만 우리나라 개발자들은 DB와 SQL에 친숙한 것 같다. 아직 OOD로 넘어오지 못한 것 같다는 생각이다. 결국 DB를 원본으로 하고 DB와 1:1 구조를 가지고 있으면서 비즈니스 로직을 객체에 분산시키는 Active Record가 필요하다고 판단이 된다.

이런 이유로 프로젝트 이름을 'Last exit for the DB believers'라고 하면 어떨까 생각도 해보았다. (물론 농담이다. ㅡ.ㅡ);

목표 사양
  • Spring jdbcTemplate와 함께 사용한다. (ActiveRowMapper 지원)
  • CoC에 따라 table과 class를 맵핑하되 애노테이션으로 설정할 수 있다.
  • Relationship 지원 belong to, has many (many-to-many 포함) 지원
  • DB schema 자동인식
  • lazy load 지원
  • paging 지원
  • clob/blob 지원
  • criteria 지원
  • 필드 변경 여부 자동인식
아직 생각하지 않는 것
  • join
  • aggregation
  • data cache
  • cascade

by 박성철 | 2008/02/07 13:33 | 프로그래밍 이야기 | 트랙백(1) | 덧글(14)

◀ 이전 페이지다음 페이지 ▶