잊지 않겠습니다.

* 사내 강의용으로 사용한 자료를 Blog에 공유합니다. Spring을 이용한 Web 개발에 대한 전반적인 내용에 대해서 다루고 있습니다.



이번 장에서는 전자정부 표준 프레임워크에 대해서 알아보도록 하겠습니다.

전자 정부 표준프레임워크는 국가 정보화 투자 효율성 제고, 중소 SI 경쟁력 확보, 선진 국가정보화 추진 기반환경의 제공이라는 목적하에 2007년 12월부터 시작하여 2010년 11월까지 총 3단계에 걸쳐 사업이 진행된 결과입니다. 
최종적으로는 효율적 운영에 필수적인 "운영환경" 및 47종의 공통 컴포넌트를 선정하고 신규 사업 및 고도화 사업을 대상으로 점진적 확대 적용을 하고 있는 추세입니다. 당장 정부쪽 SI 사업은 모두 이 전자정부 표준 프레임워크를 통해서 구축, 운영되고 있습니다. 국가대표포털, 기업 경쟁력 지원 등 총 69개의 공공,민간 정보화 사업(89개 System)에 적응되었습니다. (2011년 2월 기준) 그리고 정부 소프트웨어 기술성 평가 기준에 표준 프레임워크 도입여부를 반영함으로서 표준프레임워크 도입을 하지 않으면 정부측 SI를 할 수 없게 막아버린 효과를 가져왔습니다.


해야지 됩니다. 지금 이 바닥에서 먹고 살려면요. ㅋ



표준 프레임워크의 개발 - 개념

전자 정부 프레임워크의 구축 이유 : 정보 시스템 개발을 위해 필요한 기능 및 아키텍쳐를 미리 만들어 제공함으로써 효율적인 애플리케이션 구축을 지원하고 있습니다.
개발프레임워크는 일련의 문제 해결을 위한 추상화된 디자인을 구현한 클래스들의 집합으로서 클래스 보다는 큰 규모의 재사용을 지원하는 것을 목적으로 가지고 있습니다. 라이브러리와 개발 프레임워크의 차이는 어플리케이션의 틀과 구조를 프레임워크에서 제어하며, 프레임워크 위에서 개발자의 코드가 동작하는 차이가 있습니다. 반면에 라이브러리는 개발자의 코드 안에서 재 사용되는 것을 총칭합니다.






정부가 기대하는 전자 정부 프레임워크의 효과는 다음과 같습니다.

  1. 전자 정부 서비스의 품질 향상
  2. 정보화 투자 효율성의 향상
  3. 대/중/소 기업이 동일한 개발기반 위에서 공정경쟁을 한다.

라는 효과를 표방하고 있습니다. 개인적으로는 3번째인 대/중/소 기업이 동일한 개발기반 위에서 공정 경쟁을 한다는 것이 인상적인데요. 공정 경쟁이라는 것이 어떤 것인가.. 라는 생각은 조금 하게됩니다. 다행인 것이 예전의 my platform과 같은 기업 독자적인 framework를 따로 공부를 해야지 되는 상황은 조금 피하게 된 것 같습니다.



표준 프레임워크의 개발

실행, 개발, 운영 등 4개의 환경과 13개의 서비스 그룹, 그리고 54개의 서비스로 구성. 대기업/중소기업 대상 온라인 설문과 인터뷰 및 자료조사를 통해 구축되었습니다. 구축 과정을 보시면 아시겠지만, 설문조사를 기반으로 개발되었습니다. 현장에서 주로 사용되고 있는 open source framework가 무엇인지에 대한 설문 조사 결과가 표준프레임워크이다. 라고 할 수 있습니다. 다음은 각 open source의 선정 기준입니다.






표준 프레임워크의 개발 범위

표준 프레임워크의 개발 범위는 다음과 같습니다.





Open source framework & library

그리고, 선정된 Open source 및 Solution은 다음과 같습니다. (2010년 8월 기준)
레이어서비스명open sourcedescriptionurl
화면처리ajax supportAjax Tags 1.5jquery로 인하여 거의 사용되지 않음http://sourceforge.net/projects/ajaxtags/?source=navbar
InternationalizationSpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
MVCSpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
SecurityApache Commons Validator 1.3
UI Adaptor선정하지 않음
업무처리Process ControlSpring Web Flow 3.0http://springsource.org
Exception HandlingSpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
데이터 처리Data AccessiBatis SQL Maps 2.3
Data SourceSpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
ORMHibernatehttp://www.hibernate.org
TransactionSpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
연계 통합Naming Service SupportSpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
Integration Service선정하지 않음
Web Service InterfaceApache CXF 2.2
공통 기반AOPSpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
CacheEhcache
Compress/DecompressApache Commons Compress 1.0
Encryption/Decryptionjava simplified encrypion (jasypt) 1.5
ExcelApache POI 3.0Excel File Handling
File HandlingJakarta Commons VFS 1.0
File Upload/DownloadApache Commons FileUpload 1.2
FTPApache Commons NET 2.0
ID Generator선정하지 않음UUID 생성 기능 개발
IoC ContainserSpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
LoggingLog4j 1.3
MailApache Commons Email 1.1
Marsharling/unmarsharlingCastor 1.2, Apache XML Beans 2.4
PropertySpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
ResourceSpring 2.52012년 8월 Spring 3.1로 upgradehttp://www.springsource.org
SchedulingQuartz 1.6
Server SecuritySpring Security 2.0http://www.springsource.org
String UtilsJakarta Regexp 1.5
XML ManipulationApache Xerces2 2.9, JDOM 1.0
MobileMobile WebJquery Mobile 1.22012년 8월 선정

개발 Tool

EditorEclipse
AmaterasUML
AmaterasERD
DebugEcliopse
Unit TestJUnit
Easy Mock
Dbunit
emma
ant
maven
Buildmaven
hudson
jenkins
Configuration managementSVN
Change ManagementjTrac

보시면 아시겠지만, 35개의 open source component (개발 환경 제외)중에서 10개가 Spring입니다. 그리고 나머지 기능들에서 Spring 기능을 사용한 Web Flow와 Security를 합치면 1/3이 Spring이라고 할 수 있습니다. 거기에다가 Excel, Encrypt/decrypt와 같은 일반 기능성 component를 제외시키면 그냥 정부 표준 프레임워크는 spring framework를 사용해서 만드는 것이다. 라고 할 수도 있습니다. 이제 java를 알아도 개발을 하지 못하고, spring을 알아야지만 개발을 할 수 있는 상황이 되어버렸습니다.


정부 표준 프레임워크의 특징

  • 5개 서비스 그룹, 34개 서비스로 구성
    • 화면처리, 업무처리, 데이터처리, 연계통합, 공통기반의 5개 서비스 그룹으로 구성
    • MVC, IoC 컨테이너, AOP, Data Access, Integration 등의 핵심 서비스를 제공
  • 전자정부 프로젝트에 최적화된 오픈 소스 소프트웨어 선정
    • 34개 서비스 별 최적의 오픈 소스 소프트웨어 선정 과정을 통해 32개 오픈 소스 소프트웨어를 선정
  • 경량화된 개발프레임워크로서 사실상 업계 표준에 가까운 Spring 프레임워크를 적용
    • J2EE 표준을 준수하는 Spring 프레임워크를 채택
    • 특정 업체의 WAS나 DBMS에 독립적인 환경을 제공
  • DI 방식의 의존 관계 처리
    • Dependency Injection을 통해 개체나 컴포넌트 간의 의존성을 정의함으로써 변경용이성과 재사용성을 향상
  • AOP 지원
    • 트랜잭션, 예외처리와 같은 공통 관심 대상을 분리하여 정의함
  • MVC Model2 아키텍처 구조 제공 및 다양한 UI 클라이언트 연계 지원
    • Spring MVC를 기반으로 하며, 다양한 UI 클라이언트 연계를 위한 인터페이스를 정의함
  • 전자정부 개발프레임워크 표준 연계 인터페이스 정의
    • 표준 연계 인터페이스를 정의하여 연계 솔루션에 대한 의존성을 배제하고 독립적인 어플리케이션 개발이 가능함

이와 같이 정부 표준 프레임워크가 어떻게 구성이 되어있는지에 대해서 간략하게 알아봤습니다. 그럼 다음 장에서는 정부 표준 프레임워크를 이용한 개발 환경의 구성을 해보도록 하겠습니다.


Posted by Y2K
,

* 사내 강의용으로 사용한 자료를 Blog에 공유합니다. Spring을 이용한 Web 개발에 대한 전반적인 내용에 대해서 다루고 있습니다.


개발을 할때는 환경이 매우 중요합니다. 개발 환경을 팀의 관점으로 볼때는 단순히 업무 흐름만을 보는것은 너무 옛날 이야기가 되었습니다. 
이제 팀 단위의 개발환경에서 거의 필수가 된 항목들은 다음과 같습니다.

  1. 코드 관리 시스템
  2. 이슈 관리 시스템
  3. 자동 빌드 시스템
  4. Code Review 시스템
  5. 자동 배포 시스템
  6. 로컬 개발 서버(DB 포함) - 개발자 PC
  7. 테스트 서버 (DB 포함)
  8. 배포 서버 (DB 포함)

각 시스템이 유동적으로 연결되어 하나의 프로젝트가 완성이 되는 것이 일반적입니다.
먼저, 간단한 예를 들어보기로 하겠습니다. 여기 신입 개발자 A군과 고참 개발자 B양이 있습니다.



아침

  • B양은 이슈 관리 시스템을 통해서 자신의 팀에 주어진 일들을 확인합니다. 그리고 간단한 팀 미팅을 통해 서로간에 지금 어제 어떤 일을 했고, 오늘 어떤 일을 할 것이며, 오늘 이슈 사항이 무엇이 있는지를 파악합니다. 파악한 후, 추가로 들어온 일이 있는 경우에 그 사항을 이슈 관리시스템이 등록 또는 수정을 하고 담당자를 A군으로 지정합니다.
  • A군은 이슈 관리 시스템을 통해서 자신에게 주어진 일을 확인합니다. 그리고, 이미 분석된 업무이고, 바로 개발을 들어가게 됩니다. 먼저 코드 관리 시스템에서 소스를 최신의 것으로 Update 받습니다. 받은 Source의 History를 파악하고, DB schema의 변경사항이 있는 경우, 자신의 개발 환경에 반영을 하고 코딩을 시작합니다.

점심

  • A군은 코딩을 열심히 해서 일을 마쳤습니다. 그리고, 소스를 코드관리 시스템에 commit을 진행합니다. 소스관리 시스템은 commit된 코드가 있음을 관리자에게 알립니다.
  • B양은 A군의 코딩 내용을 보고 Code Review를 진행합니다. 맘에 안들면 불러다가, 또는 email로 깨고, reject 시킵니다. 그렇게 되면 이 코드는 반영되지 않게 됩니다.
  • A군은 다시 코딩을 합니다. 지적 받은 사항에 대해서 다시 고치고, 다시 commit을 합니다.
  • B양은 A군의 코드를 review하면서 흐뭇해하면서 코드를 accept합니다. accept된 코드는 이제 자동 빌드 시스템으로 넘어갑니다.
  • A군은 자신이 한 일에 대해서 이슈 관리 시스템에 일의 진행정도를 알리고, 완료를 시킵니다. 물론 약간의 문서 작업도 진행합니다.
  • 자동빌드 시스템은 열심히 코드를 build하고, 자동화된 test code를 모두 실행하고 그 결과를 팀원 전체에게 email로 알립니다.
  • test code가 모두 완료되면 build한 결과를 테스트 서버에 배포하게 됩니다. 이제 테스트 서버를 통해서 QC 팀들이 개발팀의 결과를 검증하게 됩니다.
  • QC 팀이 검증을 모두 마쳤습니다. 자동 배포 시스템을 통해서 실제 동작하는 서비스로 배포하게 됩니다. (모두들 수고하셨습니다.)

이러한 과정을 거치게 되는 것이 일반적인 개발회사에서의 흐름입니다. 그리고 계속되는 통합 과정을 통해, 코드의 품질을 계속해서 높이는 과정을 하게 됩니다. 그러나... 불행히도 저희 회사는 저기 위에 있는 시스템중 반도 존재하지 않습니다.

실질적인 예가 아닌, 이제 좀더 본격적인 설명에 들어가보도록 하겠습니다.


코드 관리 시스템

주로 사용되는 것은 svn과 요즘 인기를 끌고 있는 git가 있습니다. 기능으로는 code의 중앙 저장소 및 source 변경에 대한 history 관리 기능과 sync, merge 등이 있습니다. 
저희가 자주 사용하고 있지만, 조금은 다르게 사용하고 있는것 같긴 합니다. 주 기능은 code의 저장입니다. 그렇지만, 그 이상으로 중요하다고 생각되는 기능은 code의 history입니다. 어느날 갑자기 code를 받아보니 변경사항이 있었고, 그 내용이 왜, 그리고 무엇이 변경된것인지 모른다면 예전에 code를 usb같은것으로 카피해서 주는것과 차이가 없습니다. 코드를 변경했으면, 그 code를 왜 변경했는지에 대한 log를 적어주는 것이 이 시스템을 보다 더 잘 쓰는 방법입니다.

이슈 관리 시스템

많은 이슈 관리 시스템이 존재합니다. 대표적인것으로 무료로 배포되는 것들은 trac, jtrac, redmine, bugzillar 등이 있으며 상용은 jira가 있습니다. 상용으로 판매되는 jira는 정말 좋습니다. 개인적으론 구매를 해서 사용해보고 싶은 욕심이 무척 많이 듭니다. ㅠㅠ
코드 관리시스템이 코드에 대한 중앙 집중형 관리라면, 이슈 관리 시스템은 왜 그 코드를 작성하게 되었는지. 우리가 프로젝트를 완료하기 위해서는 앞으로 어떤 일들을 해야지 되는지. 그리고 지금까지 우리가 어떤 일을 해왔는지에 대한 "일, 작업, Issue, Task"에 대한 기록을 남기는 장소입니다. 이슈 관리 시스템은 코드 관리 시스템과 연동되어 코드의 변경사항이 어떤 이슈와 관련이 있는지까지 같이 보여줄 수 있습니다. 또한, 대부분의 코드 관리 시스템은 wiki라는 문서 작업 공간을 같이 제공합니다. wiki를 통해 서로간에 공유할 수 있는 내용을 기록하는 것이 가능합니다.

++ 자동 빌드 시스템, 자동 배포 시스템
이 두개의 시스템은 거의 하나로 만들어져서 사용됩니다. 이를 CI 시스템이라고 하며, hudson, jenkins와 jetBrains 사의 TeamCity가 유명합니다. CI가 CI 가 하는 일은 소스 관리 시스템과 연결되어 commit된 소스가 있는 경우, 자신이 다운받아 build 후, test code를 실행하고 그 결과를 report로 남기는 일을 반복합니다.또한 build 결과 또는 수동으로 실서버 또는 개발서버에 배포를 할 수 있기때문에 신속하고 중지 되지 않는 통합을 가능하게 하고 있습니다.





CI에 대하여 조금 더 알아보도록 하겠습니다.

다음은 CI의 기본 동작 Process를 나타내고 있습니다.

  1. Commit source code : 개발자가 자신의 code 를 commit 한다
  2. Unit Test : CI가 코드에 포함된 Unit Test code를 실행한다.
  3. CPM ( Continiuous Performance Management) : Unit Test 결과를 기록하고, Unit test의 실행 시간등을 기록한다.
  4. License check : 만약 코드 안에 상용 library등이 포함되어 있다면, license에 대한 check를 진행한다.
  5. Build : Build 및 추가 파일 복사 작업 진행
  6. Deploy : Test 환경으로의 배포 ( > QI 영역)









Code Review System

약간은 옵션적인 시스템이지만, 많은 기업들이 채용하고 있는중인 Code Review System입니다. Code Review란 간단히 사용자의 자신의 Code를 코드 관리 시스템에 Commit을 할때, 중간 단계를 하나 거치게 하는 것입니다. 그 중간단계에서 상임 개발자들이 그 코드를 평가하고, 원활히 변경된 경우에 그 코드를 코드 관리 시스템에 반영하는 절차를 추가한 시스템입니다. CodeCollaboration 이 대표적 시스템입니다.

++ 개발자 개발 환경의 구축

개발자들은 자신의 로컬 개발 환경을 반드시 갖춰야지 됩니다. 자신의 PC 자체가 원 운영 시스템과 최대한 동일할 필요가 있습니다. 이와 같은 시스템을 구축하는데 가장 큰 문제가 될 수 있는 것은 다음 방법들이 있습니다.

  1. DB
  2. OS
  3. Servlet Container (Web Server)

먼저, DB는 Project에 따라 다른 DB를 사용하게 되는 경우가 많습니다. 그럼 그 DB를 모두다 설치를 해야지 되는가. 에 대한 의문이 나오게 됩니다. 일단, 자신의 PC 상황이 최대한 좋다면.. 모든 DB가 다 설치가 되어있는 것이 좋겠지요. 그렇지 않다면 mysql이나 hsqldb가 해답이 될 수 있습니다. 그럼 db에 따라 다른 항목들은 어떻게 처리하느냐라는 문제가 남게 됩니다. 이 문제는 다음과 같이 처리합니다.

DB에 종속적인 개발을 하지 않는다. 가 우선 해결책이 될 수 있습니다.

만약에 DB에 종속적인 query를 만들어내고, SP를 실행해야지 되는 경우가 오게되면, local 개발 환경에 그 db를 반드시 설치해야지 됩니다. 개발자가 개발 환경 구축에 시간을 사용하고, 최대한 개발환경과 동일하게 구축하는 것은 당연한 요구사항입니다. 그렇지만, 단순히 crud만을 하는데, 내부에서 trim, substring 등의 함수를 이용해서 날짜 및 숫자를 뽑아내서 db에서 계산을 해서 넘어와야지 된다면, 처음 db 설계가 잘못된 것이 아닌가 생각을 해보는 것이 좋습니다.

다음은 OS입니다. 개발환경이 대체적으로 windows로 구성이 되는 반면에 서버측은 linux환경이 되는 경우가 대다수입니다. 여기서 가장 문제가 되는 것은 파일 구조입니다. 그 이유는 큰 이유는 로그 파일과 각 설정 파일의 절대적 위치때문입니다. 이 부분은 maven이나 ant를 이용한 build system으로 해결하는 것이 좋습니다. local 환경, 테스트 환경, 운영 환경에서 각각 다른 설정파일을 사용하도록 각각의 profile을 이용해서 설정하는 방법으로 해결할 수 있습니다.

다음으로 Servlet Container입니다. java는 상용 WAS들은 모두 tomcat의 servlet interface를 따르고 있습니다. 개발환경에서는 큰 부하를 견딜 필요가 없기 때문에 tomcat 또는 glass fish를 설치하는 것이 좋습니다. eclipse에 기본으로 추가 되어있는 tomcat이 가장 좋은 선택입니다. 
.net의 경우에는 윈도우즈를 사용하는 경우에는 IIS가 모두 기본으로 들어가 있기 때문에 별다른 문제가 없습니다.

일단 최대한 개인 PC와 개발 환경은 일치시키는 것이 중요합니다. 그렇지만, 현실적인 다른 문제가 발생하기도 하는데. 다음과 같습니다.


Step 01. 시작입니다. 간편합니다.




Step 02. 뭐. 이정도 즈음이야..

Step 03. 아직까지는 견딜 수 있어.

Step 04. 이제는 버틸수가 없어... 난장판이군요. ㅠㅠ

가상화 서버 또는 개발 서버를 통해서 해결을 하지만, 그 정도까지 큰 프로젝트는 아직까지는 아닙니다. 대부분의 프로젝트는 Step 03 정도면 개발이 가능합니다.


Posted by Y2K
,

Java를 1년정도 공부해보면서 이젠 슬슬 내용을 blog에 공개를 해도 될 것 같아서 공개를 해봅니다. 부끄러운 내용이지만, 도움이 될 수 있으면 좋겠습니다.


웹기술은 standalone에서 부터 시작해서, 2 tier, 3 tier, n-tier로 발전하게 되었고, 그에 따른 기술 역시 계속해서 발전해나간것을 알 수 있습니다.



standalone 시기

HTML이 처음 나오던 시기입니다. HTML에 대한 기술 습득과 http를 서비스할 수 있는 web server에 대한 기술이 발전했습니다. 지금은 누구나 하는 html 수정이 굉장한 기술이 되던 시기였습니다. 오히려 기술적으로는 web server를 직접 개발해서 서비스를 하는 문제가 더욱더 큰 이슈를 가지고 왔습니다. 그리고, 이때 개발의 방향을 바꾼 vm 기술이 나오기 시작했습니다. 전에 이야기한 .net과 java 기술이였지요. 이 두 기술 역시 처음부터 web에 집중한것은 아닙니다. 이때는 주로 사용되는 web server들이 Apache httpd 가 주로 사용이 되었고, static resource를 이용하는 형태가 주가 되었기 때문에 HTML coder 또는 web server 기술, 두 기술만이 발전하고 있었습니다. 
이때 기술의 승자는 apache 재단에서 시작한 httpd와 IIS 입니다. Http daemon 의 약자인 httpd는 아직도 Apache 서버라는 이름으로 불리우고 있습니다. (정식이름은 Apache Httpd 서버입니다.) 또한 MS의 IIS 역시 시장에서 많이 사용되는 Platform으로 사랑받기 시작했지요.


2 tier 시기

Web 기술이 폭발적으로 발전하던 시기입니다. RDBMS의 발전으로 인하여 DB의 내용에 따른 dynamic web이 발전하게 됩니다. 이때, dynamic web기술의 어려움에 의하여 여러 변형 기술들이 계속해서 나오게 됩니다. 큰 기술 흐름만을 보면 다음과 같습니다.


asp의 폭발적인 발전

기존 개발자들의 70%정도를 차지하고 있던 visual basic 개발자들을 모두 web 개발자로 만들어주는 asp와 iis가 처음 선을 보이게 됩니다. 기존 visual basic 개발자들은 모두 db와 db를 표현하는 방식에 대해서 경험이 풍부한 사람들이였습니다. 그 개발자들을 모두 web 개발자로 만드는 엄청난 일을 MS가 성공하게 됩니다. 지금보면 참 문제가 많은 개발방법으로 개발하게 되지만, 그 당시에는 최고의 기술이였으며 누구나 쉽게 웹 프로그래밍에 접근할 수 있다는 점이 가장 큰 장점이였습니다.


php의 발전 및 apache httpd의 확장

기존 standalone 서버에서 주로 사용되던 apache httpd를 이용한 dynamic web programming이 대두되게 됩니다. php는 asp의 장점을 흡수하고, 보다 쉬운 표현 방법을 제시합니다. 그리고 LAMP 라는 환경을 제시하기 때문에, 기업은 새로운 x86 windows server를 구매하는 것이 아닌 공짜로 web을 서비스할 수 있다는 점에서 기존 asp 시장을 잠식하기 시작합니다. 또한 linux 서버환경의 폭발적인 증가로 인하여 서버 환경이 기존 UNIX에서 linux 계열로 발전하게 된 계기가 됩니다.


servlet과 asp .net의 발전

asp와 php로 인하여 dynamic web application이 엄청난 발전을 하게 됩니다. 하지만 asp의 경우 언어의 특성상 큰 약점을 가지고 있습니다. page단위로 동작하게 되기 때문에, 현대적 프로그래밍 기법인 OOP를 사용할 수 없습니다. (방법은 있으나, 매우 괴악한 방법입니다.;) 점점 application이 거대화되어가면서 코드의 재 사용성 및 유지보수의 약점을 극복하기 위해서 asp와 php에 가려서 잠시 존재감을 잊어가고 있던 java와 .net이 다시 등장하게 됩니다.
두 언어는 RDBMS를 표현하는데 있어서 최선(?)의 방식을 가지고 있었으며, vm 기술의 발전으로 memory 및 performance에 강점을 가지고 있었기 때문에, 기존의 web 개발 시장을 빠르게 잠식해나가기 시작합니다.


fat client의 발전

servlet과 asp .net의 발전은 RDBMS와 dynamic web application간의 여러 문제를 모두 해결해준것같지만 사용자들에게 다양한 경험을 보여주기 위한 View를 제공하는데에 있어서, 기존의 HTML만은 한계를 가지고 있었다. 동영상과 같은 멀티미디어를 포함하기에는 기존의 HTML이 지원하지 않는 부분이 너무나 많은 영역들이 있었기 때문입니다. 멀티미디어에 대한 지원을 강화하기 위해서 나온 첫 기술이 micromedia의 Flash입니다. Flash는 멀티미디어의 지원뿐 아니라, 웹을 보다 더 아름답게 만드는데 큰 공헌을 하게 됩니다. Flash의 대성공으로 MS는 asp로 마련했던 서버 시장에 심각한 타격을 입게 됩니다. 그래서 자사의 IIS + .NET Framework 기술로 동작하는 silverlight를 출시하기에 이릅니다. 이러한 멀티 미디어의 지원과 더불어, RDBMS에 특화된 fat client들이 나오게 되는데, PowerBuilder가 바로 그것입니다. 
fat client의 발전은 기존 servlet과 asp .net 기술과 충돌을 일으키게 됩니다. 단순히 servlet과 asp .net을 fat client의 container로 이용하게 되고 모든 로직을 fat client에서 처리하게 되는 개발 방법이 한 때 유행하게 됩니다.


3 tier, n tier 시기

2 tier 가 발전한 형태인 3 tier에서는 다양한 요구사항이 생기게 됩니다. 기존 2 tier system의 확장을 통한 여러 시스템간의 결합으로 최종적으로는 enterprise system으로의 진화, 발전이 바로 그것입니다. 기존 2 tier system에서는 해결할 수 없는 기술적 이슈들이 발생하게 됩니다. 다양한 시스템들이 나오게 되고 그 시스템들간의 상호 통신에 의하여 기존 2 tier 에서 n tier로 계속되는 발전이 이루어지게 됩니다. 이 때는 다음과 같은 기술들이 발전하기 시작합니다.

script language의 발전

기존 .net과 java와는 다른 언어들이 발전하게 됩니다. 기존의 asp와 php가 OOP적 성격을 갖지 못한 단점을 해결하고 OOP적 장점과 개발의 편의성을 극대화한 script language가 발전하게 됩니다. python, ruby가 대두되기 시작하지요. 이 언어들은 기존의 객체 지향적인 특징과 asp, php와 같은 script 적 성격을 모두 갖게 됩니다. 개발의 속도, 변화 가능성에 대한 열린 대응을 토대로 이와 같은 script language가 계속된 발전을 하게 됩니다. 해외의 많은 시스템들이 하부 tier의 경우에는 ruby, python으로 개발된 것을 지금도 자주 볼 수 있습니다.

web service의 개발

n tier system의 발전은 web service가 없었다면 불가능하다고 할 정도로 web service는 n tier system에 깊이 관여되어 있습니다. web service는 기존의 tier를 종적으로나 횡적으로 모두 확장을 시키는 가장 결정적인 역활을 하게 되는 계기가 되었습니다. "Service로서의 Web"에 대한 개념은 수많은 파생적 개념을 만들어 내고, 기술적 발전을 가지고 왔습니다. 기존에는 SOAP을 기반으로 한 web service가 주로 사용되었으나, 지금은 client(javascript) 등에서의 호출 문제로 인하여 xmlrpc의 경량화된 버젼인 REST를 주로 사용하고 있습니다. 이 REST에 대해서는 다시 한번 설명할 기회를 갖도록 하겠습니다.

MVC의 발전

기존의 웹의 개발은 단순히 DB의 결과값을 웹에 표현하는 방식이였습니다. 대부분의 Business Logic은 DB에서 가지고 있고, 그 Business Logic을 web에 표현하는 방식이 대부분이였지요. 이렇게 된 가장 큰 이유중 하나는 웹으로 개발을 한 내용은 웹에 너무나 밀착되어있는 프로그램이라서, Business Logic만의 테스트가 거의 불가능하다는 것에서 시작되었습니다. 그렇지만, n tier system으로 발전해나가면서 tier만의 중복된 Business Logic을 정리 및 관리하는데 있어서 기존 프로그래밍 언어로 하고자 하는 욕구가 계속해서 발전되어 갑니다. SP에 대한 Handling과 계속되는 개발은 필연적인 중복코드와 로직의 누수가 발생하기 마련이니까요.

이때, ruby를 기반으로 한 ruby on rails가 발표됩니다. rails framework라고도 불리우는 이 framework는 기존의 web 개발 방법을 완전히 바꿔놓게 됩니다. 사용자에게 보여지는 영역인 View, Http response/request를 처리하는 Controller 마지막으로 Domain의 Business Logic을 처리하는 Model로 완벽한 영역을 분리할 수 있음을 ruby on rails는 보여주게 됩니다. 이러한 장점은 각 영역을 개발자들이 테스트를 해볼 수 있고, 영역에 대한 전문화를 분리시킬 수 있기 때문에 단숨에 웹 개발의 주도적 방법으로 대두되었습니다. java에서는 struct2가, .net에서는 asp .net mvc가 기존 ruby on rails의 사상을 반영한 MVC web framework입니다.

개발자는 지금 MVC를 중요하게 봐야지 됩니다. MVC 개발 방법은 웹뿐 아니라, 모든 application에 적용되어 있는 상황이고 각 영역에 대한 테스트를 통해서 자신의 코드의 완벽성을 스스로 검증할 수 있는 기회를 가지게 되었습니다. 에러에 대한 명확한 정의가 가능하게 되었으며, 에러가 발생했을때의 장애 처리와 같은 새로운 프로세스 정립 역시 MVC의 확립으로 가능하게 되었습니다. 이 부분은 지금까지는 개발자가 아닌, 기획이나 의사결정자들의 손에 있던 부분이였지만, 지금은 개발자들이 제시하는 방법을 선택하는 방향으로 전환이 된 상태입니다.

mobile 기기의 발전 및 확산

기존 n tier system의 발전은 획적 확장에 해당된다면 mobile 기기의 발전 및 확산은 종적 확장에 해당됩니다.기존까지 있던 web application의 대상은 모두 PC의 browser를 대상으로 하고 있었습니다. PC를 기반으로 하고 있기 때문에 PC의 특정 browser만을 target으로 하고 개발이 가능해졌지요. 그렇지만, iPhone을 시작으로 한 mobile 기기의 발전은 이러한 생각을 모두 바꾸어놓게됩니다. 누구나 가지고 다니는 mobile 기기는 언제 어디에서나 접근이 가능한 특징을 가지고 있습니다. 이는 기존보다 많은 접속을 만들어 내고, 모든 device에서 동일하게 보여야지 된다는 문제를 가지고 오게 됩니다. 그리고, mobile device의 빈약한 시스템 자원과 기존 windows system과 다른 OS 환경으로 인하여 HTML의 표준화에 대한 요구 사항이 높아지게 됩니다.

fat client의 쇠퇴와 HTML5의 대두

기존 flash와 silverlight와 같은 fat client가 mobile device에서 정상적으로 동작하지 않는 문제가 발생하게 됩니다. 이는 기존 PC에서도 windows-IE 환경 이외에서도 계속 지적되던 문제였지만, 본격적인 문제로서 국내에서는 대두되기 시작한 것은 바로 mobile 기기의 확산때문입니다. 기존 HTML에서 지원되지 않던 multimedia에 대한 지원을 비롯하여 animation과 websocket등의 표준화로 인하여 기존 flash와 silverlight가 설 자리가 없어지기 시작합니다. 지금 fat client는 flash만을 제외하고 거의 사장되어가는 분위기입니다. Flash의 경우에도 HTML5의 확산 전까지 잠시의 대체제로서의 의미 이외에는 퇴색해가는 것이 현실입니다. 기존 Flex 개발자들이 설 자리가 많이 없어지고 있지요.

Big data와 Cloud 의 대두

끊임없이 이야기가 나오고 있는 Big data와 Cloud는 mobile 기기의 발전 및 확산과 기존 web system의 오랜 발전으로 인하여 나온 기술이라고 할 수 있습니다. 기존의 RDBMS에서는 처리를 할 수 없을 정도의 데이터가 이제는 수집이 된 상태이고, 이 데이터들을 어떻게 분석을 해야지 될지. 이 데이터들을 어떻게 활용을 해야지 될지. 그리고 많은 mobile 기기에서 동시 다발적으로 들어오는 데이터를 어떻게 해야지 될지에 대한 물음에서 Big Data와 Cloud를 활용하는 방법을 찾아보는것이 방법일것 같습니다. 이러한 Big Data를 저장하기 위한 방법으로 cassandra, mongoDB, 등이 있으며 Big Data를 처리하기 위한 방법으로 Hadoop이 대두되게 됩니다. 또한 Cloud 시장은 아직 춘추전국의 시대와 같이 복잡한 상황이며, 시장 1위인 amazon의 EC2에 MS의 Azure, Google의 Google Cloud Platform등이 경쟁을 하고 있습니다.

Open source의 대두

기존에는 특정 회사의 특정 Solution 위주의 시스템에서부터 Open Source를 조합한 Open Platform이 대두됩니다. stacktrace, github 등의 사이트에서 여러 개발자들이 참여한 open source들은 어머어마한 양과 회사들이 만든 Solution보다 더 뛰어난 성능을 자랑하며 모든 시장을 휩쓸고 있습니다.

이러한 기술적 흐름속에 개발자가 익혀야지 될 기술은 어마어마하게 많은 것이 사실입니다. 그렇지만, 지금(2013)년을 기준으로 우리가 해야지 되는 기술들은 조금 목표가 정해질 수 있습니다. 어찌보면 지금까지 서론을 이야기해왔다면, 이제는 어떤 기술을 익혀야지 되고, 어떤 기술을 중심으로 다른 기술들을 곁다리로 붙여서 발전해나가야지 되는지에 대한 이정표가 될 수 있겠지요.


웹 개발자가 익혀야지 될 기술들 - 2013년 기준

.net보다는 java

대한민국에서 개발자로 먹고 살기 위해서는 .net은 이미 밀렸습니다. 행안부 기준의 정부표준 프레임워크가 java로 발표가 되고, 정부 표준 프레임워크로 모든 SI 사업이 진행되어가고 있는 현 상황에서 더이상 .NET을 한다는 것은 이제는 개발자로서의 자신을 스스로 학대하는 일 그 이상, 그 이하도 안되게 되었습니다. 일단 java에 집중하는 것이 맞습니다. 그리고 세계적으로도 java의 놀라운 발전은 이제 JVM의 성능이 Ch2.의 성능까지 따라왔다는 이야기가 나올정도로 최적화 및 향상이 되었습니다. 더이상 느리다는 이야기가 나오지를 않는 추세지요.

spring

정부표준프레임워크의 핵심입니다. 정부표준프레임워크는 spring으로 구성이 되어 있고, spring으로 돌아갑니다. 일단 spring을 잘 할 줄 알면, 정부 표준 프레임워크의 반이상은 해결하고 들어간다고 보면 됩니다. spring에 대한 소개에서 다시 이야기를 하겠지만, spring 자체가 java의 표준화에 영향을 주고 있고, java의 표준 자체가 spring이 되어가고 있는 현실입니다. 이 추세로 간다면 spring은 하나의 open source framework가 아닌 java의 일부분이 될 수 있을 것 같습니다.

DB 기술

dao(data access object) 기술은 오래되었지만, 그 기술을 표현하는 방식은 계속해서 바뀌어왔습니다. DB의 특정 데이터들을 보이기 위한 VO로 접근하는 방식과 DB역시 객체화 하여 객체적으로 접근을 하는 ORM 방식으로 크게 나뉘고 있습니다. 현장에서는 국내는 VO 방식을 더 많이 사용하고 있으나, 세계적으로는 ORM 방식이 압도적으로 많이 사용하고 있습니다. 두가지 모두 알아야지 됩니다.

Controller 기술

spring의 세부 기술중 하나입니다. spring에 대해서 잘 안다면...에 포함되는 기술 영역이긴 하지만, HTTP가 어떻게 활용되어가는지에 대한 이해가 필요합니다. 이는 Servlet Container(ex:tomcat)에 대한 이해와도 같이 연결이 됩니다. web이 돌아가는 시스템에 대한 이해라고 할 수 있습니다.

Modeling 기술

Modeling은 소위 말하는 '업무분석' 과정입니다. 업무를 분석하고 분석한 업무를 programming language로 구현 가능한 형태로 추상화를 시키는 과정을 의미합니다. 개발자의 생각의 방향은 학교에서 자주 들은 Divide & conquer 입니다. 작게 나누고, 하나하나 해결해나가고. 그 해결한 조그마한 것들을 다시 붙이는 작업들이 필요합니다.

개발 방법론

소프트웨어 공학은 매우 변화가 심한 학문입니다. 건축학에서 많은 개념들을 차용해왔으나, 지금은 건축학과는 많이 다르다는 것을 인지하고 접근하고 있습니다. 요즘 S/W 개발 방법론의 추세는 agile 개발 방법론입니다. agile에 대해서는 차후에 보다 더 심도있게 짚어보도록 하겠습니다.

패턴 (Pattern)

개발 방법론과 매우 유사한 분야입니다. 개발을 할때, 코드를 최적화 하는 패턴들이 존재합니다. 패턴을 익히는 것보다는 패턴을 이용해서 개발자들끼리의 의사소통이 가능해져야지 됩니다. 개발자들끼리 사용하는 약어가 되는 경우가 꽤나 많습니다. 그리고 책을 통해서 학습을 할때도 유용합니다.

단위 테스트 (Unit Test)

개발자는 자신이 만든 모든 s/w를 테스트할 수 있어야지 되고, 그 테스트한 결과로서 자신의 s/w의 품질을 증명할 수 있어야지 됩니다. "내가 하면 되었는데.", "어제는 되었는데." 식의 이야기는 곤란합니다. in/out이 결정나면 그 in/out에 대한 명확한 테스트를 하고 그 테스트 결과를 보여줄 수 있어야지 됩니다. 또한 s/w의 규모가 크면 클수록 그 코드를 검증할 수 있어야지 됩니다. 이제는 테스트를 돌리기 위해서 개발을 한다. 라는 말이 나올 정도로 테스트는 일반화된 기술입니다. 자동화된 테스트를 구성하는 능력은 반드시 필요합니다.



Posted by Y2K
,

Spring 3.1에서 강화된 @Configuration을 사용한 설정에서 재미있는 @EnableXX annotation을 이용한 @EnableOrm을 만들어보고자한다. 

먼저, 요구사항

1. 기본적으로 BoneCP를 이용
2. packagesToScan 을 통해서 entity가 위치한 package를 지정해줄 수 있어야지 된다.
3. Hibernate와 Hibernate를 이용한 JPA를 모두 지원하는 형태로 구성한다.
4. Ehcache를 사용할 수 있어야지 된다. 

기본적으로 구성되는 pom.xml의 구성은 다음과 같습니다. 

        <dependency>
            <groupId>com.jolbox</groupId>
            <artifactId>bonecp</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.mysema.querydsl</groupId>
            <artifactId>querydsl-core</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.mysema.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.mysema.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.mysema.querydsl</groupId>
            <artifactId>querydsl-sql</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>log4j-over-slf4j</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>provided</scope>
        </dependency>

먼저, @EnableOrm interface는 다음과 같이 정의 될 수 있습니다. 

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(OrmConfigurationSelector.class)
public @interface EnableOrm {
    String[] packagesToScan() default {};

    boolean enableCache() default false;

    boolean showSql() default false;

    OrmType ormType() default OrmType.Hibernate;
}

public enum OrmType {
    Hibernate, Jpa;
}

packageToScan과 enableCache, 그리고 console 창에 sql query문을 출력해야지 되는 경우를 기본적으로 고려해줄 수 있습니다.  그리고 OrmType을 통해서 기본 Hibernate를 이용한 Orm과 Jpa를 이용하는 두가지를 모두 사용할 수 있도록 합니다.  OrmType에 따라 각각 Load되는 Configuration이 바뀌어야지 되기 때문에 Import class는 ImportSelector를 구현한 객체여야지 됩니니다. 

ImportSelector를 구현한 객체는 다음과 같이 구성됩니다. 

public class OrmConfigurationSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        Map<String, Object> metadata = importingClassMetadata.getAnnotationAttributes(EnableOrm.class.getName());
        OrmType ormType = (OrmType) metadata.get("ormType");
        if (ormType == OrmType.Hibernate) {
            return new String[] { HibernateConfiguration.class.getName() };
        } else {
            return new String[] { JpaConfiguration.class.getName() };
        }
    }
}

그리고, Hibernate를 이용할 때와 JPA를 이용할 때의 공통 코드가 존재하는 abstract 객체를 하나 만들어주는 것이 좋을 것 같습니다. 기본적으로 Hibernate JPA를 사용할 예정이기 때문에 공통적으로 DataSource와 Hibernate Property는 완벽하게 중복되는 코드가 만들어질테니까요. 
공통 Configuration객체인 OrmConfiguration객체의 기능은 다음과 같습니다.

1. BoneCP datasource 제공
2. Hibernate Property의 제공
3. enableCache, packateToScan, showSql 등 protected 변수의 제공

OrmConfiguration 객체는 다음과 같이 구성될 수 있습니다. 

public abstract class OrmConfiguration implements ImportAware {
    public static final String HIBERNATE_DIALECT = "hibernate.dialect";
    public static final String CONNECT_USERNAME = "connect.username";
    public static final String CONNECT_PASSWORD = "connect.password";
    public static final String CONNECT_DRIVER = "connect.driver";
    public static final String CONNECT_URL = "connect.url";

    public static final String HIBERNATE_SHOW_SQL = "hibernate.show_sql";
    public static final String ORG_HIBERNATE_CACHE_EHCACHE_EH_CACHE_REGION_FACTORY = "org.hibernate.cache.ehcache.EhCacheRegionFactory";
    public static final String HIBERNATE_CACHE_USE_QUERY_CACHE = "hibernate.cache.use_query_cache";
    public static final String HIBERNATE_CACHE_USE_SECOND_LEVEL_CACHE = "hibernate.cache.use_second_level_cache";
    public static final String HIBERNATE_CACHE_REGION_FACTORY_CLASS = "hibernate.cache.region.factory_class";

    @Autowired
    protected Environment env;

    protected boolean showSql;
    protected boolean enableCache;
    protected String[] packagesToScan;

    @Bean
    public DataSource dataSource() {
        BoneCPDataSource dataSource = new BoneCPDataSource();
        dataSource.setUsername(env.getProperty(CONNECT_USERNAME));
        dataSource.setPassword(env.getProperty(CONNECT_PASSWORD));
        dataSource.setDriverClass(env.getProperty(CONNECT_DRIVER));
        dataSource.setJdbcUrl(env.getProperty(CONNECT_URL));
        dataSource.setMaxConnectionsPerPartition(20);
        dataSource.setMinConnectionsPerPartition(3);
        return dataSource;
    }

    @Bean
    public HibernateExceptionTranslator hibernateExceptionTranslator() {
        return new HibernateExceptionTranslator();
    }

    @Bean
    public abstract PlatformTransactionManager transactionManager();

    protected Properties getHibernateProperties() {
        Properties properties = new Properties();
        properties.put(HIBERNATE_DIALECT, env.getProperty(HIBERNATE_DIALECT));
        if (enableCache) {
            properties.put(HIBERNATE_CACHE_REGION_FACTORY_CLASS, ORG_HIBERNATE_CACHE_EHCACHE_EH_CACHE_REGION_FACTORY);
            properties.put(HIBERNATE_CACHE_USE_SECOND_LEVEL_CACHE, true);
            properties.put(HIBERNATE_CACHE_USE_QUERY_CACHE, true);
        }
        return properties;
    }

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        if (env.getProperty(HIBERNATE_DIALECT) == null || env.getProperty(CONNECT_USERNAME) == null
                || env.getProperty(CONNECT_PASSWORD) == null || env.getProperty(CONNECT_DRIVER) == null
                || env.getProperty(CONNECT_URL) == null) {
            throw new IllegalArgumentException("properties is not completed! check properties (hibernate.dialect, "
                    + "connec.username, connect.password, connect.driver, connect.url)");
        }
        Map<String, Object> metaData = importMetadata.getAnnotationAttributes(EnableOrm.class.getName());
        enableCache = (boolean) metaData.get("enableCache");
        packagesToScan = (String[]) metaData.get("packagesToScan");
        showSql = (boolean) metaData.get("showSql");
    }
}

기본적인 Property들은 모두 Properties 파일에 정의되지 않으면 에러가 발생하도록 객체들을 구성하였습니다. 이제 HibernateConfiguration을 한번 구성해보도록 하겠습니다. 

@Configuration
@EnableTransactionManagement
public class HibernateConfiguration extends OrmConfiguration implements HibernateConfigurer {
    private static final String HIBERNATE_SHOW_SQL = "hibernate.show_sql";

    @Bean
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(dataSource());
        setLocalSessionFactoryBean(sessionFactory);
        return sessionFactory;
    }

    @Override
    @Bean
    public PlatformTransactionManager transactionManager() {
        HibernateTransactionManager transactionManager = new HibernateTransactionManager();
        transactionManager.setDataSource(dataSource());
        transactionManager.setSessionFactory(sessionFactory().getObject());
        return transactionManager;
    }

    @Override
    public void setLocalSessionFactoryBean(LocalSessionFactoryBean localSessionFactoryBean) {
        Properties properties = getHibernateProperties();
        if (showSql) {
            properties.put(HIBERNATE_SHOW_SQL, "true");
        }
        localSessionFactoryBean.setHibernateProperties(properties);
        localSessionFactoryBean.setPackagesToScan(packagesToScan);
    }
}


기본적으로 항시 사용되는 SessionFactory와 그에 대한 설정부분을 Load 시켜주고, PlatformTransactionManager를 return 시켜주는 매우 단순한 @Configuration class입니다. 

이제 JpaConfiguration입니다. 
@Configuration
@EnableTransactionManagementpublic class JpaConfiguration extends OrmConfiguration implements JpaConfigurer {
    @Override
    public void setEntityManagerFactoryBeanProperties(LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
        entityManagerFactoryBean.setPackagesToScan(packagesToScan);
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean entityManagerFactory = new LocalContainerEntityManagerFactoryBean();
        setEntityManagerFactoryBeanProperties(entityManagerFactory);
        entityManagerFactory.setDataSource(dataSource());
        entityManagerFactory.setJpaVendorAdapter(hibernateJpaVendorAdapter());
        entityManagerFactory.setJpaProperties(getHibernateProperties());
        return entityManagerFactory;
    }

    @Bean
    public HibernateJpaVendorAdapter hibernateJpaVendorAdapter() {
        HibernateJpaVendorAdapter hibernateJpaVendorAdapter = new HibernateJpaVendorAdapter();
        hibernateJpaVendorAdapter.setShowSql(showSql);
        return hibernateJpaVendorAdapter;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Override
    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setDataSource(dataSource());
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }
}


둘의 코드는 거의 완전히 동일합니다. Hibernate를 이용할 것인가, 아니면 Jpa를 이용할 것인가에 대한 기본적인 차이만이 존재합니다. 
테스트 코드 구성은 다음과 같습니다. 

@Configuration
@EnableOrm(ormType = OrmType.Hibernate, enableCache = true, packagesToScan = "com.xyzlast.domain.configs", showSql = true)
@PropertySource(value = "classpath:spring.properties")
@ComponentScan("com.xyzlast.domain.repositories")
public class TestHibernateConfiguration {
    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        PropertySourcesPlaceholderConfigurer configHolder = new PropertySourcesPlaceholderConfigurer();
        Properties properties = new Properties();
        properties.setProperty("org.jboss.logging.provier", "slf4j");
        configHolder.setProperties(properties);
        return configHolder;
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestHibernateConfiguration.class)
public class HibernateConfigurationTest {

    @Autowired
    private ApplicationContext applicationContext;

    @Before
    public void setUp() {
        assertThat(applicationContext, is(not(nullValue())));
    }

    @Test
    public void dataSource() {
        DataSource dataSource = applicationContext.getBean(DataSource.class);
        assertThat(dataSource, is(not(nullValue())));
    }

    @Test
    public void transactionManager() {
        PlatformTransactionManager transactionManager = applicationContext.getBean(PlatformTransactionManager.class);
        assertThat(transactionManager, is(not(nullValue())));
    }

    @Test
    public void sessionFactory() {
        SessionFactory sessionFactory = applicationContext.getBean(SessionFactory.class);
        assertThat(sessionFactory, is(not(nullValue())));
    }
}

이제 Hibernate와 JPA에 따른 각각의 configuration을 따로 구성하지 않아도 되는 멋진 코드가 만들어졌습니다.
회사에서 다른 팀원들이 사용할 수 있도록 jar를 만들어서 사내 nexus 서버에 올려야지 되겠습니다. ㅋㅋ




Posted by Y2K
,
<mvc:annotation-driven>
이 설정될 경우, 여기에 따른 여러가지 설정이 많이 이루어지게 된다. 
먼저 Spring 문서에 따르면, 

 1. Support for Spring 3′s Type ConversionService in addition to JavaBeans PropertyEditors during Data Binding. A ConversionService instance produced by the org.springframework.format.support.FormattingConversionServiceFactoryBean is used by default. This can be overriden by setting the conversion-service attribute. 
2. Support for formatting Number fields using the @NumberFormat annotation 
3. Support for formatting Date, Calendar, Long, and Joda Time fields using the @DateTimeFormat annotation, if Joda Time is present on the classpath. 
4. Support for validating @Controller inputs with @Valid, if a JSR-303 Provider is present on the classpath. The validation system can be explicitly configured by setting the validator attribute. 
5. Support for reading and writing XML, if JAXB is present on the classpath. 
6. Support for reading and writing JSON, if Jackson is present on the classpath. 

와 같은 일들이 벌어지게 된다. 

여기서 주의할 점은 1번 항목. ConversionService가 default로 설정이 된다는것이다. ConversionService가 이미 설정이 되어 있기 때문에 Spring source에서 보면 다음과 같은 항목에 의하여 에러가 발생하게 된다.
        public void setConversionService( ConversionService conversionService ) {
               Assert .state ( this. conversionService == null, "DataBinder is already initialized with ConversionService");
               this .conversionService = conversionService ;
               if ( this .bindingResult != null && conversionService != null ) {
                      this .bindingResult . initConversion( conversionService );
               }
        }
따라서, Converter 를 이용한 @InitBinder는 사용할 수 없게 되고 에러를 발생시키게 된다. 이 경우에, @InitBinder를 이용하기 위해서는 PropertyEditorSupport를 상속받아 등록시키는 방법을 사용할 수 밖에 없게 된다. 을 통해서 설정되는 것을 xml로 표현하면 다음과 같다.
    
        
    
     
    
    

    
        
            
                
                
            
        
        
            
                
                
                    
                
                
                
                





            
        
    

    
        
        
            
                
            
        
    
위에서 주석처리 되어 있는 항목들은 해당 외부 라이브러리들이 존재하면 사용되게 된다.



Posted by Y2K
,