News from 3월, 2010

  2010/03/02
최근에 읽은 책..
Last changed: 3월 02, 2010 20:59 by 자바지기

올해 책을 100권 읽겠다는 목표를 세웠지만 책 읽는 습관은 어떠해야할까? 글에서 이야기 했듯이 많은 책을 읽기 보다는 한 권의 책을 정독하는데 집중하려고 하고 있다. 그래도 지금까지의 습관이 쉽게 고쳐지지 않는지라 재미있으면 그냥 편하게 읽고 넘어가는 경우가 대부분이다. 단, 책을 읽으면서 나중에 다시 한번 읽으면 좋겠다고 생각하는 책에 표시를 하고 있다.

그 동안 읽어야지 하면서 계속 미루고 있던 책인데 책 두께가 있는지라 생각보다 많은 시간을 걸려서 읽었다. 물론 책의 내용은 체 게바라의 일대기를 다루고 있어서 좋았지만 책 사이 사이에 나오는 상당히 생소한 이름들 때문에 책 흐름을 유지하는데 힘들었다. 특히 등장인물이 많으면 책을 잘 따라가지 못하는데 이 책은 처음부터 끝까지 정말 많은 이름이 등장해 흐름을 끊는 경우가 많았다. 정말 마지막 100페이지는 의무감으로 읽은 듯하다.

그래도 그 동안 체 게바라에 대하여 막연함을 가지고 살았는데 이 책을 통하여 그의 열정적인 삶을 되돌아 볼 수 있는 계기가 되었다. 자신이 생각하는 바를 그대로 행동으로 옮긴 사람.. 자신을 사랑했지만 자신보다 타인을 더 사랑했던 체 게바라.. 몇 일 전에 있었던 사내 강의에서는 그가 남긴 한마디를 다른 이들과 공유할 수 있어 더 좋았다.

우리 모두 리얼리스트가 되자.

그러나 가슴 속에 불가능한 꿈을 간직하자.

나 또한 항상 불가능한 꿈을 꾸며 살고 있지만 현실주의자가 되려고 노력하고 있다.

지난 3일 연휴 때 읽은 두 권의 책이다. 생각했던 것보다 너무 재미있고, 책이 잘 먹어가는 바람에 3일에 걸쳐서 두권을 읽었다. 이 책을 읽으면서 1800년대부터 조선이 일본에게 망하게 된 이유를 이 책을 보면 분명하게 느낄 수 있다. 1800년 즈음이나 지금이나 별반 달라진 것은 없는 듯하다. 어쩌면 그 당시에 영향을 미쳤던 노론 벽파의 영향이 지금까지 우리 사회를 지배하고 있을지도 모른다는 느낌이 든다. 정조가 5년만 더 살았더라면 지금의 역사는 어떻게 바뀌었을까?

이 책을 읽으면서 역사적인 사건에 대해서 알게 된 것도 좋았지만 그 보다 더 피부로 느낄 수 있었던 것은 유배에 대한 생각이다. 유배를 당한 사람에게 있어서 정말 가슴 아픈 일이지만 항상 바쁘게 살아가는 현대인에게 있어서 유배와 같은 생활이 필요한 것은 아닐까? 항상 바쁘게 돌아가는 세상 속에서 현실적으로 돈을 벌기 위하여 일하고 있지만 가끔씩은 조용하게 자신만의 시간을 가지면서 지금까지 공부한 지식을 정리하는 시간을 가질 필요가 있지 않을까? 대학 교수들이 몇 년에 한번씩 안식년을 가지는 것처럼 지식 사회를 살고 있는 지식 노동자에게 있어서도 안식년이 필요하다는 생각이다. 한번 쯤은 자신이 지금까지 쌓은 지식을 정리하고 한단계 성숙시킬 필요가 있기 때문이다. 지금까지 우리가 쌓은 지식은 현장에서 필요한 지식을 익혀 바로 활용하는 것에만 집중했는데 이 같은 지식은 깊이를 쌓는데 한계가 있기 때문이다. 물론 소프트웨어 개발 지식은 빠르게 변하기 때문에 이 같은 시간이 불필요하다고 생각할 수 있지만 소프트웨어의 근간이 되는 핵심 지식은 잘 변하지 않기 때문이다. 이 같은 지식은 지금과 같이 빨리 빨리를 외치는 상황에서는 쉽게 익히기 어려운 지식이며, 습관이다. 이 같은 지식은 많은 삽질과 연구를 통해서 자신의 것으로 만들 수 있으며, 한 단계 성숙시킬 수 있을 것이다. 유배로 인해 정약용과 그 가족의 삶은 힘들고 고닲았겠지만 유배의 삶 속에서 집대성한 지식은 200년 가까이 지나고 있는 지금까지도 영향을 미치고 있는 것이라 생각한다.

Posted at 02 3월 @ 8:54 오후 by 자바지기 | 2 Comments
  2010/03/09
Batch Job 배포 방법 및 배포 방법에 따른 장,단점 비교
Last changed: 3월 09, 2010 21:31 by 자바지기

최근 Spring Batch에 대한 사내 기술 지원 업무를 진행하면서 고민했던 것이 "Batch Job을 어떻게 배포할 것인가?"였다. Batch Job을 잘 개발하는 것도 중요하지만 어떻게 배포하느냐에 따라서도 운영 비용이 크게 차이가 날 수 있기 때문이다. Batch Job을 배포하면서 Batch 모니터링 툴도 어떻게 배포하는 것이 좋을지에 대한 고민도 같이 하게 되었다. 이 같은 고민을 하면서 배포 유형을 어떻게 가져갈 수 있을까에 대하여 정리해 봤다.

  • Batch 관리툴이 있는 경우
    • Batch Job과 Batch 관리툴을 분리하여 운영한다.
    • Batch Job과 Batch 관리툴을 통합하여 운영한다.
  • Scheduler 유형에 따른 경우
    • 시스템 Crontab 기능을 활용한다.
    • Quartz와 같은 Scheduler Framework를 활용한다.
  • Batch Job의 분리 유무
    • 각각의 Batch Job을 분리하여 관리하는 경우
      • 단독 Application으로 만들어서 운영
      • 웹 컨테이너 또는 OSGi 컨테이너 기반으로 운영
    • 각각의 Batch Job을 통합하여 관리하는 경우
      • 단독 Application으로 만들어서 운영
      • 웹 컨테이너 또는 OSGi 컨테이너 기반으로 운영

생각할 수 있는 모든 방법을 고려하다보니 경우의 수가 무지 많다. 위 각각의 방법으로 Batch Job을 관리할 때의 장,단점을 살펴보면 다음과 같다.

Batch Job과 Batch 관리툴 분리 vs 통합

Batch 관리툴이 필요없다면 이에 대한 고려는 필요 없겠지만 Batch 관리툴이 필요한 경우에는 어떻게 운영하는 것이 좋을지에 대하여 고려해야 한다.

Batch Job과 Batch 관리툴 통합

Batch Job과 Batch 관리툴을 통합해서 관리해야 할 경우의 장점은 운영할 때 고려해야 하는 요소가 하나 줄어든다는 것이다. 이와 같이 통합해서 운영하는 경우는 각각의 Batch Job을 독립적으로 운영할 만큼의 대용량 Batch Job이 아니고, 운영을 쉽게 하는 것이 목적인 경우 유용한 접근 방법이다. 따라서 이와 같은 판단을 하는 경우 Batch 관리툴과 모든 Batch Job을 하나의 웹 컨테이너를 통하여 관리하는 경우가 일반적이다.
Batch Job과 Batch 관리툴을 통합해서 운영할 경우 Batch Job과 Batch 관리툴이 의존 관계가 있기 때문에 각각에서 문제가 발생할 경우 다른 영역에 영향을 미칠 수 있다. 또한 Batch Job과 Batch 관리툴에 변경이 발생했을 때 독립적으로 배포하기 힘들다.

각각의 Batch Job의 크기가 작고, 실행에 큰 부담이 없다면 운영의 편의성을 위해서 이 방법을 선택하는 것이 좋을 것으로 생각한다. 특히 Batch Job이 많지 않은 상황에서는 이 방법으로 운영하고 문제가 발생하는 경우 이후 분리하는 것도 좋은 전략이다.

Batch Job과 Batch 관리툴 분리

앞의 통합과는 반대로 독립적인 배포 및 운영이 가능하지만 관리해야할 부분이 늘어나기 때문에 운영 비용이 증가한다. 이 방법은 대량의 Batch 작업을 해야 하는 경우와 Batch Job과 Batch 관리툴의 의존 관계를 만들지 않고자 할 때 선택할 수 있는 좋은 전략이라고 생각한다.

각 Batch Job 분리 vs 통합

각각의 Batch Job을 분리해서 관리하느냐 통합해서 관리하느냐도 앞의 Batch 관리툴의 분리와 통합과 같은 전략으로 접근할 수 있다. 각 Batch Job의 독립성이 중요하고 실행 비용이 크다면 분리하는 것이 바람직한 선택이며, 그렇지 않은 경우에는 통합해서 관리하는 것이 운영 비용을 줄이기 위하여 좋은 선택이 될 수 있다.

Crontab과 Scheduler Framework(예. Quartz)

Batch Job을 실행하기 위하여 Scheduler 기능을 활용해야 하는데 일반적으로 Crontab과 Scheduler Framework를 이용하는 경우가 많다. 각각의 장,단점에 대하여 살펴보면 다음과 같다.

Crontab은 crontab 명령을 이용하여 쉽게 Scheduler를 등록하는 것이 가능하다. 또한 Scheduler와 Batch Job이 분리되어 있기 때문에 Scheduler에 변경이 발생하는 경우 Batch Job과 독립적으로 시간을 변경할 수 있다. 하지만 Batch Job과 같이 관리되지 않기 때문에 서버를 이전하는 경우나 운영 담당자가 바뀌는 경우 누락하는 경우가 많다. Batch 관리툴까지 없는 상태라면 Batch Job이 실행되지 않아서 버그나 장애가 발생하는 경우를 종종 경험한다.

Quartz와 같은 Scheduler Framework는 Batch Job과 같이 소스 코드를 관리하고 배포 단위를 같이 가져갈 수 있기 때문에 Batch Job을 운영하기 위해서는 좋은 선택이지만, 시간이 변경되는 경우 설정을 변경하고 소스를 재배포해야 하는 불편함이 있으며, 개발자가 새로운 API를 익혀야하는 부담이 있다.

하지만 Batch Job을 운영해 본 경험으로 봤을 때 새로운 API에 대한 학습 비용과 소스 코드 재배포에 대한 비용보다는 장애가 발생하지 않도록 운영하는 것이 운영자의 입장에서는 더 중요하기 때문에 가능하면 Crontab 보다는 Scheduler Framework를 활용하는 것이 더 좋은 선택이지 않을까 생각한다.

위와 같이 각각에 따른 장,단점이 있기 때문에 Batch Job과 Batch 관리툴에 대한 배포 전략은 다음과 같이 가져가는 것이 좋지 않을까?

  • 대용량의 Batch Job이 없고, 운영 비용을 줄이는 것이 목적이라면 Batch 관리툴, 모든 Batch Job을 하나의 웹 컨테이너에 배포하여 관리한다. 만약 대용량 Batch Job이 발생한다면 해당 Batch Job에 대해서만 독립적으로 관리한다.
    • Batch Job과 Batch 관리툴을 개발해 보면 각각의 개발 환경이 다른 경우가 많다. 따라서 개발은 모듈로 분리하여 개발하고 배포만 같이하는 전략도 좋은 선택이 될 수 있다.
  • 각 Batch Job 간의 독립적인 배포 및 운영이 중요하다면 각 Batch Job과 Batch 관리툴을 분리하여 배포한다.
  • Batch Job에 대한 Scheduler는 가능한 Quartz와 같은 Scheduler Framework를 활용하고, 각 Batch Job 기준으로 관리하여 분리할 필요가 있을 때 분리하기 용이하도록 한다.

위와 같이 Batch Job과 Batch 관리툴에 대한 배포 전략을 수립하고 나서 좀 더 좋은 방법이 없을까 고민하다가 OSGi 컨테이너인 Spring DM Server에 눈길을 돌리게 되었다. Spring DM Server라면 각 Batch Job별로 Stop, Start, 재배포가 가능하지 않을까 생각하면서 접근하기 시작했다. 이렇게 해서 Spring DM Server에 배포할 Batch Job Bundle을 만들고 삽질을 한 결과 내가 원하는 형태로 배포하는 것이 가능하다는 결론을 얻었다. Spring DM Server에 Batch Job을 배포할 경우 얻게 되는 장,단점은 다음과 같다.

장점

  • 서버 운영 중에도 각 Batch Job 별로 소스를 배포하는 것이 가능하다.
  • 서버 운영 중에 각 Batch Job 별로 Batch의 Stop, Start가 가능하다.
  • Batch Job이 실행 중에 Stop을 실행할 경우 Batch Job이 완료되는 것을 보장해 준다.

단점

  • Batch Job을 OSGi Bundle로 만들어야 하기 때문에 학습 비용이 발생한다.
  • Spring DM Server에 대한 운영 노하우가 없어 이 또한 학습 비용과 경험이 필요하다.
  • 단순한 Batch Job을 개발하는 경우 복잡도가 너무 높을 수 있다.

Spring DM Server를 활용할 경우 좋은 점도 많지만 아직 경험이 많지 않다는 것과 작은 Batch Job까지 OSGi Bundle로 만들 필요가 있을까라는 생각이 든다. 아직 경험이 없는 상태라 그럴 수 있지만 기술적인 욕심 때문에 쉽게 풀 수 있는 문제를 너무 어렵게 접근하는 것은 아닌가라는 의구심을 가지게 되었다.

아직 Spring DM Server에 대한 운영 노하우가 없어 실무에 바로 적용하기는 힘들겠지만 경험이 쌓이고, 운영 노하우가 생긴다면 가져갈만한 전략이라고 생각한다. 현재로서는 Spring Dynamic Module로 개발하는 것이 익숙하지 않기 때문에 많은 삽질을 해야겠지만 경험이 축적되고 모듈 기반으로 개발해 재사용성을 높이는 노하우를 쌓는다면 장기적인 관점에서는 좋은 선택이 되리라 생각한다.

Posted at 09 3월 @ 10:09 오후 by 자바지기 | 7 Comments
  2010/03/11
Spring Integration과 통합했을 때의 Batch Job 관리
Last changed: 3월 11, 2010 12:03 by 자바지기
Labels: spring, batch, integration, channel

Spring Batch를 기반으로 Batch Job과 Batch 관리툴을 어떻게 만들고 배포하느냐에 관심을 가지다 보니 상당히 다방면에 관심을 가져야겠다는 생각이 든다. 최근에 Spring과 자바 진영의 변화가 얼마나 빠르게 진행되고 있는지 느끼기도 했지만 한편으로는 Spring의 복잡도가 너무 높아져서 쉽게 접근하기 힘들겠구나라는 생각이 들었다. 자바를 처음 접하는 개발자가 힘들어 하듯이 Spring도 그런 상태에 도달했구나라는 생각이다. 물론 내부까지 속속들이 이해하지 않은 상태에서 단지 사용만 한다면 더 쉽고, 편하게 생각하는 개발자들도 있을 듯 하지만 문제가 발생했거나 프레임워크가 제공하지 않는 새로운 형태의 기능을 추가하기 위해서는 내부 구조까지 이해할 필요가 있다. 지금까지는 Spring Batch를 분석하면서 최근에 느낀 점이다. 지금부터 본론으로 들어가보자.

Spring Batch를 분석하다보니 Spring BatchSpring Integration을 통합해서 사용하면 좋겠다는 생각이 들었다. 특히 얼마 전에 올라온 Practical Use of Spring Batch and Spring Integration 문서를 보면 Spring Batch와 Spring Integration을 어떻게 접목해서 사용할 수 있는지 아이디어를 얻을 수 있다. 2009년 SpringOne에서 발표한 Automating Operations with Spring Batch and Spring Integration 동영상을 보면 Spring Batch와 Spring Integration에 대한 내용을 볼 수 있는데 Spring Integration에 대하여 처음 접해서인지 바로 이해가 되지는 않는다. 관심이 있는 사람들은 한번 살펴보면 많은 도움이 될 듯하다.

Spring Batch와 Spring Integration을 통합해서 사용하는 가장 좋은 예제는 현재 개발 진행 중인 Spring Batch Admin 소스를 분석하면 많은 도움이 될 듯하다. Spring Batch와 Spring Integration을 통합하고 있어서 Spring Batch와 Spring Integration에 대한 기본 지식이 없는 상태에서 Spring Batch Admin 소스를 보면 다소 어렵게 느껴질 수 있다. 따라서 먼저 Spring Batch와 Spring Integration에 대한 기본적인 개념과 구조를 이해하고 Spring Batch Admin 소스를 보는 것이 더 빠른 접근 방법일 듯하다.

몇 일간 Spring Batch, Spring Integration, Spring Batch Admin과 관련한 문서와 소스를 보면서 Spring Batch Job을 개발해서 운영할 때 다음과 같은 구조로 운영할 수 있겠다는 생각이 들어 간단하게 정리해 본다.

먼저 Spring Batch 운영에 대한 구조를 이해하기 위하여 Spring Integration의 Service Activator와 Channel Adapter에 대하여 이해해야 한다. 물론 Spring Integration의 다른 개념도 이해할 필요가 있지만 이 글에서는 다루지 않겠다. 더 자세한 내용은 Spring Integration Reference 문서를 참고하기 바란다.

Service Activator
Service Activator는 Input Channel을 통하여 전달된 메시지를 이용하여 Service Instance(우리들은 흔히 이야기하는 비지니스 로직을 담당하는 Object)를 실행하는 역할을 한다.

위 그림에서 보는 바와 같이 Input Channel에 전달된 메시지를 있는지를 확인하고 메시지가 있다면 이 메시지를 이용하여 비지니스 로직을 수행하는 역할을 한다. 만약 Service Instance 영역에서 Return 값이 있다면 Output Channel을 통하여 다른 영역에 전달하는 것이 가능하다.

Channel Adapter
Channel Adapter는 Spring Integration 내에서 사용하는 Message Chnnel과 다른 시스템을 연결하는 역할을 한다. File, HTTP Request, JMS Message에서 전달되는 메시지를 Spring Integration의 Channel Message 형태로 바꾸거나, Spring Integration의 Channel Message를 File, HTTP Request, JMS Message 형태로 변환하는 역할을 한다.

Spring Integration의 위 두가지 개념을 접한 후 Spring Batch Job을 다음과 같은 구조로 운영하는 것이 가능하겠다는 생각이 들었다.

먼저 Batch Job 앞단에 Job-requests라는 Input Channel을 만든다. Job-requests에 메시지가 전달되면 ServiceActivator가 JobLaunchingMessageHandler를 실행하여 각각의 BatchJob을 실행하는 구조이다. 이와 같은 구조로 가져갈 경우 Job-requests Input Channel에 실행하고자하는 Job 이름을 전달하면 각각의 Job을 실행할 수 있는 방식이다.

이와 같이 Job-requests Input Channel을 열어주면 다음과 같이 다양한 방식으로 Batch Job을 실행 및 관리하는 것이 가능하다.

위 그림에서 각각의 상황에 따른 시나리오를 살펴보면 다음과 같다.

1. 특정 디렉토리에 파일이 추가되는 경우 Batch Job이 실행되어 해당 File을 읽어 Batch 작업을 실행해야 한다. 이 같은 요구사항의 경우 주기적으로 특정 디렉토리에 파일이 추가되었는지 모니터링하고 있다가 파일이 추가되면 FileToJobRequestAdapter를 통하여 Spring Integration의 Message 형태로 변화하여 Job-requests Input Channel에 Batch Job 실행을 요청한다.
2. Batch 관리툴에서 관리자가 특정 Batch Job에 대한 실행을 요청한다. Batch 관리툴과 Batch Job이 같은 JVM에서 동작하고 있다면 StringToJobRequestAdapter을 실행한다.
3. Batch 관리툴에서 관리자가 특정 Batch Job에 대한 실행을 요청한다. Batch 관리툴과 Batch Job이 다른 JVM에서 동작하고 있다면 JMS, RMI, Http Adapter를 통하여 실행한다.
4. Quartz, Crontab과 같은 Scheduler에 의하여 특정 Batch Job을 주기적으로 실행한다. Scheduler와 Batch Job이 같은 JVM에서 동작하고 있다면 StringToJobRequestAdapter을 실행한다.
5. Quartz, Crontab과 같은 Scheduler에 의하여 특정 Batch Job을 주기적으로 실행한다. Scheduler와 Batch Job이 다른 JVM에서 동작하고 있다면 JMS, RMI, Http Adapter를 통하여 실행한다.

위 그림은 이해를 돕기 위하여 각 영역의 동작을 최대한 단순하게 그렸다. Batch 관리툴, Scheduler, Batch Job이 서로 다른 영역에서 동작하고 있다면 위 구조보다 훨씬 더 복잡한 구조가 될 가능성이 높다. 위 두개의 그림을 통합하여 하나로 만들어 보면 전체 흐름을 좀 더 명확하게 이해할 수 있을 듯 하다.

위에서 살펴본 바와 같이 Spring Integration의 Channel을 통하여 Batch Job을 Launch, Restart, Stop을 할 수 있도록 한다면 다른 시스템과의 통합을 더 쉽게 가져갈 수 있다. 물론 위와 같은 구조로 운영하는 것은 복잡도를 증가시키는 결과를 가져올 수 있다. 따라서 반드시 위와 같은 구조로 가져갈 필요는 없다. 단지 다른 시스템과 연계하거나 하나의 Batch Job을 다양한 방식으로 운영할 필요가 있는 경우에는 위와 같은 구조로 개발해 유연성을 확보할 수도 있다.

아직 Spring Integration에 대한 이해도 높지 않은 상태라 Spring Batch와의 통합할 경우 이 정도의 통합이 가능하지 않을까 생각해봤다. 앞으로 이해도가 높아지고 실무에 적용사례가 있다면 더 다양한 구조로 개발, 운영하는 것이 가능하리라 생각된다.

Posted at 11 3월 @ 12:35 오후 by 자바지기 | 1 Comment
  2010/03/12
Selenium과 Continuous Integration 통합을 통한 자동화
Last changed: 3월 12, 2010 20:56 by 자바지기
Labels: selenium, continuous, integration, xvfb

2008년 Selenium 기반으로 웹 UI에 대한 테스트 코드를 만들고, UI에 대한 자동화된 테스트 환경을 만들기 위하여 노력했던 기억이 난다. 그런데 2008년에 마지막으로 진행하고 싶었던 부분이 Selenium과 지속적 통합툴(Continuous Integration)과의 통합 작업이었다. 일반적으로 지속적 통합툴은 모니터가 없는 개발 서버이며, 리눅스 환경에서 동작하기 때문에 브라우저를 통해서 테스트를 진행하는 Selenium의 경우에는 지속적 통합툴을 활용하기 힘들었다. 시간적인 여력 때문에 2008년에는 지속적 통합툴까지 연동하지는 않고 필요할 때 로컬 컴퓨터에서 테스트하는 방식으로 진행했다.

한 동안 잊고 지내다가 어제 갑자기 이 숙제에 대한 해결책을 찾고 싶어졌다. 그래서 오랜만에 "Selenium Continuous Integration'을 검색어로 온라인 문서를 찾아봤다. 그랬더니 정말 내가 원하는 해결책을 제시하는 문서들이 많이 보였다. 그렇게 해서 이틀 동안 총 4시간 정도의 시간을 투자해서 성공했다. 이 작업을 위하여 참고한 문서는 다음과 같다.

위 문서를 통하여 리눅스, 유닉스 환경에서 Selenium을 테스트하기 위해서는 Xvfb (X Windows Virtual Frame Buffer)을 사용하면 된다는 것을 알게 되었고, 현재 Ant 버전과 Maven 버전으로 개발이 되고 있다는 것을 확인할 수 있었다. 나는 Maven 플러그인을 활용해서 진행했다.

Headless X11 with Xvfb 문서에 Maven 설정에 대해서는 상세하게 설명이 되어 있어서 쉽게 세팅할 수 있었다. 문제는 Xvfb를 설치하고 설정하는 과정에서였다. 생각보다 쉽게 성공할 수 있었는데 처음에는 로컬에 설치되어 있는 Cygwin에서 Xvfb를 설치하고 테스트를 했는데 자꾸 에러가 발생하고 해결책을 찾는데 많은 시간을 보냈다. 도저희 해결책을 찾을 수가 없어서 Cygwin는 포기하고 자바지기 개발 서버에 다시 세팅하기 시작했다. 그랬더니 Xvfb 세팅이 너무 쉽게 끝나 버렸다. 어제 회식이 있었던 관계로 "설마 그냥 되는 건 아니겠지?"라는 마음으로 회식하러 갔는데 마무리를 하지 못해서 찜찜한 마음이었다. 아침에 출근하자마자 다시 테스트를 위한 빌드 환경을 만들고 테스트를 했는데 바로 성공해 버렸다. Maven을 빌드하면서 Xvfb가 실행되고, Selenium Server Start, Firfox Launch, Test 과정이 흘러가는 모습을 보면서 어찌나 기분이 좋던지..

이제 마지막 남은 한 가지 작업은 소스 코드를 Commit하는 순간 빌드 실행, 컨테이너에 소스 배포를 하면 Selenium Test가 자동으로 실행되도록 하는 부분이다. 이 부분까지 완성된다면 단위 테스트 뿐만 아니라 웹 UI를 통한 통합 테스트까지 완전하게 자동화할 수 있을 것으로 생각한다.

Posted at 12 3월 @ 9:34 오후 by 자바지기 | 0 Comments
  2010/03/13
안드로이드 스터디 진행과 관련하여..
Last changed: 3월 13, 2010 20:56 by 자바지기

제가 지난 번에 안드로이드 스터디를 진행한다면..이라는 글을 통하여 안드로이드 스터디를 진행해 보려고 생각했습니다. 그래서 스터디에 참여할 의사가 있는 사람들에 대하여 사전 조사를 했고, 저도 안드로이드 책을 통해서 예제를 실행해 봤습니다. 제가 책의 모든 부분에 대하여 실습을 진행해 보지는 않았지만 이 내용으로 스터디를 할 필요가 있을까라는 생각이 들었습니다. 그냥 관심이 있다면 개인적으로 공부해도 충분한 수준이 아닐까라는 생각이 들었습니다.

따라서 안드로이드만을 가지고 스터디를 진행할 경우 주제가 좀 작겠다는 생각이 들더군요. 그리고 과거 스터디에 비하여 활발하게 토론할 수 있는 부분도 많지 않겠다는 생각이 들더군요. 커리큘럼에 대해서는 좀 더 생각해보고 결정하는 것이 스터디의 활성화를 위해서도 좋겠다는 생각입니다. 스터디 신청하신 분들 미안합니다. 좀 더 고민하고 스터디 진행 여부와 커리큘럼 정하도록 하겠습니다.

Posted at 13 3월 @ 9:25 오후 by 자바지기 | 0 Comments
  2010/03/17
Spring Framework에서 ApplicationContext간의 parent,child 관계 만들기
Last changed: 3월 17, 2010 09:09 by 자바지기
Labels: applicationcontext, parent, child

이번에 Spring Batch에 대한 지원 업무를 하면서 다음과 같은 요구사항이 생겼습니다. 기존에 이미 Quartz를 통하여 구현되어 있는 Batch Job이 이미 존재하는 상태이고, 각 Quartz Job이 실행될 때마다 ApplicationContext을 새로 생성해서 실행하는 구조로 되어 있었습니다. 이렇게 동작하다보니 각 Batch Job 간의 독립성을 보장하기 위한 목적으로는 좋지만 매번 같은 인스턴스를 만들어야 하는 비용적인 부담이 발생하게 됩니다.

왜 이와 같이 관리하느냐고 의아해 하는 분들도 있겠지만 그 때의 요구에 따라서 충분히 만들어질 수 있는 구조라 생각합니다. 이와 같이 독립적으로 실행하고 독립적으로 관리할 경우 Batch Job 간의 의존 관계를 만들려고 해도 만들기 쉽지 않은 구조가 되기 때문에 개발자가 많거나 개발자의 변경이 많은 경우에는 나름 좋은 선택이라고 생각합니다. 물론 개인적으로 이 선택에 찬성하지는 않지만요.

그런데 이 같은 구조를 한번에 모두 바꾸기에는 운영하는 측에서 부담스러워하더군요. 그래서 단계적으로 변경해 가기로 했습니다. 먼저 각 Batch Job에서 공통적으로 사용하는 부분을 서블릿 컨테이너가 시작할 때 WebApplicationContext로 만들어 재사용을 하고 이후 각각의 Batch Job에서 생성한 ApplicationContext와 parent/child 관계를 유지할 수 있도록 만들자는 것이 하나의 안이었습니다. 물론 Quartz와 Spring에 대한 통합도 하지 않고 현재의 구조를 최대한 유지하면서 Spring Batch로 단계적으로 전환하는 전략을 구사하고 있습니다.

물론 처음부터 모두 바꾸는 전략도 좋지만 정말 하고자하는 일이 Batch에 대한 모니터링이 가능한 환경을 구축하는 것이기 때문에 Spring Batch로 전환하는데 집중하기로 한 것입니다. 좋은 전략이라고 생각합니다. 이 시점에 정말 중요한 것은 Batch Job을 통일시키는 것이지 Scheduler를 변경하는 것은 아니기 때문입니다.

이 같은 요구사항을 만족시키기 위하여 ApplicationContext간의 parent/child 관계를 동적으로 만들고 Batch Job이 완료되면 parent/child 관계를 해제해야 상황이 발생했습니다. 이 문제에 대한 해결책을 찾기 위하여 검색해 봤는데 딱히 좋은 해결책이 없더군요. 그 동안 웹 애플리케이션을 개발할 때는 서블릿 컨테이너를 통하여 한번에 ApplicationContext를 생성했기 때문에 딱히 고민하지 않던 문제였으니까요. 그래서 Spring MVC를 사용할 때 parent/child 구조가 발생하기 때문에 가능하다고 생각했죠.

그래서 찾아보게 된 것이 ApplicationContext의 API내에 해결 방법이 있을 듯 하더군요. 그런데 의외로 쉽게 해결책을 찾았습니다. Spring API가 이미 잘 지원하고 있더라고요.

package net.javajigi.ac;

import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class ApplicationContextLoadTest {
  @Test
  public void loadBeanFromChild() throws Exception {
    ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("parent.xml");
    ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext(new String[] {"child.xml"}, true, parent);
    
    Person person = child.getBean(Person.class);
    Address address = child.getBean(Address.class);
    assertNotNull(person);
    assertNotNull(address);
    child.close();
  }
}

Person과 Address의 초기화와 소멸되는 과정에 로깅을 하고 테스트 진행해 보면 결과를 확인할 수 있습니다. 테스트를 할 수 있도록 나머지 소스도 첨부하면 다음과 같습니다.

Person.java
package net.javajigi.ac;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

public class Person implements InitializingBean, DisposableBean {
  @Override
  public void afterPropertiesSet() throws Exception {
    System.out.println("Person start!!");
  }

  public String getName() {
    return "name";
  }

  @Override
  public void destroy() throws Exception {
    System.out.println("Person end!!");
  }
}
Address.java
package net.javajigi.ac;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class Address implements InitializingBean, DisposableBean {
  @Override
  public void afterPropertiesSet() throws Exception {
    System.out.println("Address start!!");
  }

  public String getCity() {
    return "yong in si";
  }

  @Override
  public void destroy() throws Exception {
    System.out.println("Address end!!");
  }
}
parent.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  <bean id="person" class="net.javajigi.ac.Person"/>
</beans>
child.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
  <bean id="address" class="net.javajigi.ac.Address"/>
</beans>
Posted at 17 3월 @ 9:49 오전 by 자바지기 | 0 Comments

3월 2010  
Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      

3월 09, 2010
3월 13, 2010