MongoDB 소개

DB/MongoDB 2013. 1. 7. 17:54


Mongodb는 NO-SQL DB중 하나이다. NoSQL은 문자그대로 'No SQL'이라고도 하고 'Not Only SQL'의 약어라고도 한다.
개인적으로 'No SQL'은 제품 자체의 특성, Game Changer로서의 'NoSQL'을 강조하는 의미로 강한 도전감을 내포하고 있고
'Not Only SQL'은 RDBMS의 Alternative로서의 'NoSQL'의 존재론적 의미를 내포하고 있다고 생각한다.
MongoDB는 NoSQL제품군중 국내에서 가장 많이 활용된 프러덕트이기도 하다.[1]
경쟁제품으로 카산드로, HBASE등이 있다. NoSQL 솔루션이 각광 받으면서 여러 제품군들이 나오면서 각 제품의 효용성에 대한 찬반이 격화되고 있고 몽고 디비도 성능에 대한 이슈[2]와 이에 대한 반박[3]이 대두되고 있다.

NoSQL제품군은 DB성격에 따라 Key-Value Database, Document Database, BigTable Database, Graph Database로 분류하는데 MongoDB는 Document 데이터 베이스로 분류된다. MongoDB와 경쟁제품으로 많이 비교되는 HBase와 Cassandra는 BigTable제품군으로 분류되는데, 사실 용도가 전혀 다른 성격을 가진 NoSQL제품군들로 경쟁상대가 아니라 상호보완적인 제품으로 봐야한다. 흔히 이쪽 계열의 엔지니어들이 벌이는 불필요한 논쟁중 하나가 프로그래밍 랭귀지 우열에 대한 것이다. 
혹자는 이 문제가 철학/신념의 문제라고 하지만 실상은 헤게모니싸움. 더 솔직히 말하면 밥그릇 싸움에 불과하다.
프로그래밍 언어는 그 어떤 범용 언어도 모든일을 최고로 효율적으로 해결해낼수 없다. 각각 특성에 맞게 사용하면 되는게 정답이다. 시장에서 많이 쓰이는 언어들이라면 차이와 장단점이 존재할뿐 우열같은건 애초에 없다. NoSQL제품군도 마찬가지다. 차이에 따라 용도에 맞는 사용을 하면 되는것이다. 어떤일이든 최적의 방법으로 해결해주는 Silver Bullet같은건 존재하지도 존재할수도 없기때문이다.
MongoDB는 Document-Oriented NoSQL솔루션으로 Schema-Free, Full Text Indexing을 지원한다. 
이쯤하면 생각나는 솔루션이 있다. 바로 Lotus Domino Notes. Domino Notes라... 
Document Database가 가장 적합한 용도는 어디일까? 한장 한장 비슷해보이지만 들여다 보면 다른, 그래서 RDBMS로 일반화시키긴 어려운, 그리고 데이터들이 서로 연관관계가 적은 독립적인 데이터셋이 많은 응용 프로그램. 
그룹웨어나 이런 블로그 같은것들. 웹 서비스 데이터의 1차 저장소로 사용하면 좋을듯하다. 
게다가 유연한 데이터 구조와 중복데이터를 허용하는 특성때문에 빈번한 필드 추가와 삭제/변경이 일어날수 있는 웹서비스에 적합한 솔루션으로 보인다.

몽고디비의 공식 홈페이지는 http://www.mongodb.org/ 이다. 설치파일및 관련 도큐멘트를 모두 얻을수 있다.

구글 트렌드로 본 MongoDB / Cassandra / HBase 관심도 - 카산드라의 경우에는 동일한 이름의 사람의 검색이 더많아 부득이하게 cassandra db로 하였다. 이에 결과가 상당히 부정확하다. 


- MySQL에 비해선 아직 턱없이 부족한 관심도. 하지만 MySQL의 관심도 하락 추세가 무엇을 의미하는지는 생각해봐야한다.

[1] "Hadoop과 MongoDB를 이용한 로그분석시스템 구축사례" http://blog.naver.com/PostView.nhn?blogId=nts_story&logNo=50116614473&categoryNo=15&viewDate=&currentPage=1&listtype=0
"몽고DB Daum MyAgora 도입사례" http://rockfactory.tistory.com/119

[2]“몽고DB 쓰지 마세요”…왜?  http://www.bloter.net/archives/103400 
    위 기사의 Base가된 포스트 http://pastebin.com/raw.php?i=FD3xe6Jt
[3]위 기사에 대한 반박  http://news.ycombinator.com/item?id=3202959



출처 - http://garden.egloos.com/10000179/post/233269






요즘 대용량 데이타 처리 때문에, NoSQL을 머릿속에만 올려놓고, 근래에나 되서 이래서는 안되겠다 해서 직접 자료를 찾아보고 있습니다.

NoSQL은 Cassandra, HBase, Mongo, Riak등을 후보군으로 뒀는데,

Cassandra는 FaceBook에서 Donation해서 만든 분산 DB로 개인적으로는 가장 신뢰가 가기는 했지만, 국내의 많은 블로그 포스팅등을 읽어보면, 안정성이나 사용성이 떨어진다는 것이다. 즉 제품은 좋은데 야생마처럼 잘 쓰지 못하면 모쓰는 제품이라는 이야기. 일단 후보로 남겨놓고 패스.

HBase는 Hadoop File System (HDFS)를 기반으로 설계되었는데, 검색해보니 생각보다 많이 사용이 안되는 것 같아서 패스
Riak도 신생이라서 패스

결국은 Mongo와 Cassandra에서 고민하게 되었는데,
신생 MongoDB가 얼마전부터 사람들 입에 많이 입에 오르내리고 있다. 검색을 해봐도 많이 나오고
이는 즉 사용이 쉽다는 것을 의미하고 또한 10gen이라는 회사에서 제품에 대한 Ownership을 지고 서포트와 컨설팅 그리고 라이센스를 제공하고 있다. 둘다 오픈소스(?)이긴 하지만 자기네들만이 사용하기 위해 만든 Cassandra와는 태생 자체가 다르다는 사실

요즘 분산 아키텍쳐를 보면 대부분 비슷한것이 앞단에 Load Balancing을 해주는 Proxy 를 두고, 뒤에 데이타 처리를 하는 Processing Node를 두는 것이 일반적인데, SWIFT도 글코, MogileFS도 글코, 분산 처리 환경인 Gearman이나 Hadoop도 결국은 비슷하다. 아니나 다를까, MongoDB도 유사한 구조를 갖는다.

일단 기능적인 특징을 보면

Indexing이 가능하다.
이말은 즉 빠른 Search가 가능하다는 이야기인데, 문서를 찾아보니, Index는 메모리에 저장되기 때문에, 메모리 크기에 영향을 많이 받는다. 즉 Deployment설계할때, 하드웨어의 Memory 사이즈가 중요한 Factor 라는 것

GridFS 기반의 Blob 데이타 저장 지원
GridFS라는 분산 파일 시스템을 사용하여 Binary 데이타 저장이 가능하다. 일반적인 아키텍쳐에서 meta 정보를 DBMS에, binary를 File System에 나눠서 저장할때, 이로 인해서 발생되는 데이타 일관성에 불일치를 방지할 수 있다는 점에서는 혁신적인데.. 문제는...
국내의 어느 블로거가 테스트한 데이타 http://symplog.tistory.com/entry/MongoDB-MongoDB-GridFS-%EB%B6%80%ED%95%98%ED%85%8C%EC%8A%A4%ED%8A%B8 를 보면, 파일 업로드 다운로드 성능이 그리 뛰어나지 않은 듯 하다.
큰 파일을 저장할때, 파일을 Chunk 단위로 나눠서 다운로드, 업로드 하는데 이는 메모리 사용면에서 효율성을 제공한다. (한꺼번에 다 읽거나 쓸때 한꺼번에 Flush를 하면 파일을 메모리에 가지고 있는 동안, 파일 사이즈가 크면 Out Of Memory를 유발할 수 있기 때문에..) 1.7 버전 이하에서는 4M, 1.7 이상에서는 16M의 Chunk Size를 제공하는 것 같은데. 
문제는 Opendedup에서도 테스트해봤지만, 이 Chunk 단위로 파일을 나누는 작업이 보통 일이 아니라는, 일단 태생 자체가 작은 Blob 데이타를 저장하기 위함이지 대용량 파일을 저장하기 위함은 아닌 것 같은데,
http://blog.wordnik.com/12-months-with-mongodb 블로그를 보면 12billion (약 120억개)의 레코드를 저장하고, 여기에 음악 파일을 저장하는 것을 보면 가능하다고도 볼 수 있다. 보통 음악 파일이 4M 안팍인것을 감안하면 괜찮은 시나리오인 듯 하나 500GB가 넘어가는 비디오 파일을 저장할때는 어느정도 성능을 감당할 수 있을지는 미지수 이다.
만약에 안정적으로 GridFS가 대용량 파일을 저장할 수 있는 구조를 제공한다면 사람들이 SWIFT,MogileFS,GlusterFS를 사용하지 않고 모두 MongoDB를 사용해야 하지 않을까? 
이 부분은 나름 테스트가 필요한 부분으로 남겨놓고 넘어간다.

Querying
아울러 RDBMS 와 같은 Query를 제공한다. (물론 RDBMS보다 한참 못 미치기는 하지만)
Key/Value Store만 지원하는 다른 NoSQL에 비하면 매력 적인 기능

Replication
http://www.mongodb.org/display/DOCS/Master+Slave
Master-Slave Replication도 지원하네, Query Off Loading 구현도 가능하겠다.

Sharding
그외에 자체적으로 데이타 Sharding 아키텍쳐를 지원한다. 요즘 이게 유행인지 MySQL 최신 버전도 자체적으로 Sharding을 지원한다. Sharding을 사용하면 1000개의 Shard까지는 거뜬히 지원할 수 있는 것 처럼 나오는데, 이건 테스트 하기는 어려울테고, 성능 데이타를 레퍼런스 하는 수 밖에

일단 완성도나 기능들이 높아 보이는 것 같은데..
깔아서 테스트해보고, 10gen 에서 컨설팅 불러서 직접 들여다 봐야 몬가 나오지 않을까?
=== 첨언 ===
구조를 살펴보니, 앞에서 언급했던 것처럼 SWIFT나 MogileFS와 상당히 유사하다
앞단에 Load Balancing 역할을 해주는 mongos 라는 프로세스들이 뜨고
뒷단에 실제 데이타를 저장하는 mongod라는 프로세스들이 뜨는데, 여기서 재미있는 것은 데이타 Replication을 하는데, 각 Shard당 3개의 인스턴스를 제공하도록 구성을 권장한다. Swift등에서 흔히 이야기 하는 3 Copy다. 데이타 안정성등을 위하는 건데. (딱 봐도, 하드웨어 비용이 장난 아니겠다.)

더불어서 MogoDB는 Cassandra나 HBase에 비해서 나은 성능을 갖는데 앞에서 설명한 바와 같이 Memory를 이용한 Indexing등으로, 반대로 이야기 하면 Memory가 충분히 있어야 한다는 이야기고, 비싸다는 이야기다.

큐브리드 블로그에 보면 재미있는 내용이 있는데 http://blog.cubrid.org/dev-platform/nosql-benchmarking/

Cassandra and HBase is for processing full-scale large amounts of data, while MongoDB can be used quickly, schema-free when using a certain amount of data.

MongoDB adopts a documented-oriented format, so it is more similar to RDBMS than a key-value or column oriented format.

MongoDB operates on a memory base and places high performance above data scalability. If reading and writing is conducted within the usable memory, then high-performance is possible. However, performance is not guaranteed if operations exceed the given memory. Therefore, MongoDB should be used as a medium or small-sized storage system.

한마디로, 성능은 좋지만 빅데이타는 Cassandra나 HBase를 쓰고 중소형에만 MongoDB를 쓰라는 것이다.
RDBMS에 유사하고 강력한 Feature, 사용의 편리성의 입장에서 MongoDB가 국내외에서 많은 사용층을 가지고 있는 것이 대강 이해는 된다. 한편으로는 MongoDB의 한계를 벗어날만한 데이타를 아직까지 사용해본 적이 없다는 반증도 될것이다. 10~20억 데이타는 내가 아는한에서는 RDBMS에서도 크게 문제가 없다. 문제는 10~20억을 넘는 100억, 1000억개의 데이타 핸들링에도 MongoDB가 버텨 줄것이냐인데.. 데이타 한건당 대략 10K만 잡아도 용량이 1Peta 이다. 3TB 노드를 300개 정도 연결해야 한다는 것인데... MongoDB에서 보통 1000개의 Instance를 이야기를 하니 이론상으로는 가능할것 같기는 한데
첫번째는 어렵지 않을까? 하는 생각이고, (그만한 레퍼런스가 있냐?) 두번째는 만약에 된다고 하더라도 돈이 엄청 들어갈것 같은 느낌이다. Swift도 MogileFS도 저가라고는 말하지만 소프트웨어가 저가인거지 3Copy로 하드웨어 구성을 벤더 제품으로 하면 마찬가지라는... (Commodity 하드웨어라면 몰라도..)
  이래 저래 자료를 찾아볼 필요가 있다.



출처 - http://bcho.tistory.com/601






MongoDB 탐구

이 데이터베이스 관리 시스템이 매우 인기 있는 이유를 확인한다.

Joe Lennon, 모바일관련 개발자, Core International

요약:  이 기사에서는 프로덕션 환경에서 데이터베이스를 확장할 수 있는 기능을 제공하는, C++로 작성된 오픈 소스 문서 지향 데이터베이스 관리 시스템인 MongoDB에 관해 배웁니다. 기존의 관계형 데이터 베이스 시스템(RDBMS)과 비교하여 문서 지향 데이터베이스가 갖고 있는 이점을 확인합니다. MongoDB를 설치하고 데이터베이스 콜렉션과 문서 작성을 시작합니다. RDBMS 데이터베이스 관리자와 개발자에게 익숙한 방식으로 키/값 저장소에 효율성을 제공하는 MongoDB의 동적 쿼리 기능을 시험합니다.

기사 게재일:  2011 년 9 월 20 일 


MongoDB란?

최근에는 기존의 관계형 모델과는 다른 데이터베이스 관리 시스템에 대한 관심이 증가하고 있다. 이 중심에는 NoSQL이라는 개념이 있는데, 이는 데이터베이스 상호 작용에 SQL을 사용하지 않는 데이터베이스 소프트웨어를 총괄하는 용어이다. 주목할 만한 NoSQL 프로젝트 중 하나는 JSON 형태의 문서 콜렉션으로 데이터를 저장하는 오프 소스 문서 지향 데이터베이스인 MongoDB이다. MongoDB가 다른 NoSQL 데이터베이스와 다른 점은 쿼리가 매우 쉽게 변환되기 때문에 관계형 데이터베이스를 MongoDB로 쉽게 변환할 수 있는 강력한 문서 지향 쿼리 언어에 있다.

MongoDB는 C++로 작성되어 있다. MongoDB는 JSON의 2진 버전인 BSON을 사용하여, 키/값 쌍으로 데이터를 유지하는 JSON 형태의 문서에 데이터를 저장한다. MongoDB가 다른 문서 데이터베이스와 구별되는 한 가지 기능은 SQL문을 MongoDB 쿼리 함수 호출로 매우 간단하게 변환하는 기능이다. 이 기능을 이용하면 조직에서 현재 사용 중인 관계형 데이터베이스를 쉽게 마이그레이션할 수 있다. 또한, 주요 운영 체제와 프로그래밍 언어에서 사용 가능한 2진 파일과 드라이버를 사용하면 매우 간단하게 설치하여 사용할 수 있다.

MongoDB는 GNU AGPL(Affero General Public License) 버전 3.0에 따라 라이센스가 부여된 데이터베이스를 사용하는 오픈 소스 프로젝트이다. 이 라이센스는 카피레프트 제한이 소프트웨어를 사용하는 데는 적용되지 않고 배포에만 적용되는 허점을 보완한 GNU GPL의 수정 버전이다. 물론, 일반적으로 클라이언트 디바이스에 설치되지 않고 클라우드에 저장되는 소프트웨어는 이점이 중요하다. 사실상 소프트웨어가 배포되지 않기 때문에 일반 GPL을 사용하는 경우에는 라이센스 조항을 회피할 수 있다는 사실을 인식할 수 있다.

AGPL은 데이터베이스 애플리케이션 자체에만 적용되며 MongoDB의 다른 요소에는 적용되지 않는다. 개발자들이 다양한 프로그래밍 언어로 MongoDB에 연결하는 데 필요한 공식 드라이버는 Apache License Version 2.0에 따라 배포된다. MongoDB 문서는 CCL(Creative Commons license)에 따라 사용 가능하다.

문서 지향 데이터베이스

문서 지향 데이터베이스는 기존의 관계형 데이터베이스와는 매우 다르다. 문서 지향 데이터베이스는 테이블과 같은 경직된 구조에 데이터를 저장하지 않고 느슨하게 정의된 문서에 데이터를 저장한다. 관계형 데이터베이스 시스템(RDBMS) 테이블에서는 열을 새로 추가하려면 테이블 자체의 정의를 변경해야 한다. 따라서 비록 널 값을 갖게 될지라도 열이 기존의 모든 레코드에 추가된다. 이는 RDBMS의 엄격한 스키마 기반 설계로 인한 것이다. 그러나 문서를 사용하는 경우에는 기타 모든 문서를 변경하지 않고도 개별 문서에 속성을 새로 추가할 수 있다. 이는 문서 지향 데이터베이스가 일반적으로 스키마를 사용하지 않도록 설계되기 때문이다.

또 다른 기본적인 차이점은 문서 지향 데이터베이스는 문서 간의 엄격한 관계를 제공하지 않는다는 점이다. 이러한 점은 문서 지향 데이터베이스가 스키마 없는 설계를 유지하는 데 도움이 된다. 이점은 관계에 의존하여 데이터 스토리지를 표준화하는 관계형 데이터베이스와는 매우 다른 점이다. 문서 데이터베이스에서는 "관련" 데이터를 별도의 스토리지 영역에 저장하는 대신에 문서 자체에 삽입한다. 각 참조는 추가 쿼리를 필요로 하기 때문에 이렇게 하는 것이 관련 데이터가 저장된 또 다른 문서에 참조를 저장하는 것보다 더 빠르다.

이러한 기능은 데이터가 상위 문서 안에서 독립적으로 존재하는 것이 적합한 많은 애플리케이션에서 매우 잘 동작한다. 이에 해당하는 예(MongoDB 문서에도 있음)로는 블로그 포스트와 주석이 있다. 주석은 단일 포스트에만 적용되므로 주석을 블로그 포스트와 분리해서 생각하는 것은 타당하지 않다. MongoDB에서는 블로그 포스트 문서에 해당 포스트의 주석을 저장하는 comments 속성이 있다. 관계형 데이터베이스에서는 ID가 기본 키인 주석 테이블과 포스트 테이블 그리고 주석이 속하는 포스트를 정의하는 중간 맵핑 테이블 post_comments가 존재하게 된다. 이로 인해 매우 간단해야 할 것들이 불필요하게 매우 복잡해진다.

그러나 관련 데이터를 별도로 저장해야 하는 경우에는 MongoDB에서 별도의 콜렉션을 사용하여 쉽게 이러한 작업을 수행할 수 있다. 또 다른 좋은 예는 MongoDB 문서에 고객 주문 정보를 저장하는 것이다. 일반적으로 고객 주문 정보는 고객 정보, 주문 자체, 주문 품목 및 제품 정보로 구성된다. MongoDB를 사용하면 고객, 제품 및 주문 정보를 개별 콜렉션에 저장하게 되지만, 품목 데이터는 관련된 주문 문서 안에 삽입된다. 그러면, 관계형 데이터베이스에서 사용한 것과 같은 외부 키 형태의 ID를 사용하여 제품 고객 콜렉션을 참조한다. 이러한 하이브리드 방식은 단순하기 때문에 MongoDB는 SQL로 작업하는 데 익숙한 개발자들에게 좋은 선택이 된다. 그렇긴 하지만, 다른 콜렉션에서 데이터를 참조하는 대신에 문서 내부에 데이터를 삽입하면 성능을 대폭 개선할 수 있으므로 각각의 개별 유스 케이스를 대상으로 취해야 하는 접근 방식을 신중하게 결정해야 한다.

기능 개요

MongoDB는 단지 기본적인 키/값 저장소가 아니다. MongoDB의 다른 기능 중 일부를 간략하게 살펴보도록 하자.

  • 공식 2진 파일은 Windows®, Mac OS X, Linux® 및 Solaris에서 사용 가능하며 소스 배포판을 이용하여 직접 빌드할 수도 있다.
  • 공식 드라이버는 C, C#, C++, Haskell, Java™, JavaScript, Perl, PHP, Python, Ruby 및 Scala에서 사용 가능하며, 다른 언어에서는 광범위한 커뮤니티 지원 드라이버를 사용할 수 있다.
  • 모든 문서 속성에서 기준을 사용하여 데이터를 찾을 수 있게 하는 임시(Ad-hoc) Javascript 쿼리. 이러한 쿼리는 SQL 쿼리의 기능을 반영한 것으로 SQL 개발자는 이 쿼리를 이용하여 MongoDB 쿼리를 매우 간단하게 작성할 수 있다.
  • 쿼리에서 정규 표현식 지원
  • MongoDB의 쿼리 결과는 limit(), skip(), sort(), count(), distinct()  group()을 포함하여 필터링과 수집 및 정렬에 필요한 다양한 함수를 제공하는 커서에 저장된다.
  • 고급 수집용 map/reduce 구현
  • GridFS를 사용하는 대용량 파일 스토리지
  • RDBMS 형태의 속성 인덱싱 지원, 여기에서는 선택된 문서 속성에서 직접 인덱스를 작성할 수 있다.
  • 힌트, 설명 계획 및 프로파일링을 사용하는 쿼리 최적화 기능
  • MySQL과 비슷한 마스터/슬레이브 복제
  • 표준화된 데이터를 필요로 하는 참조 쿼리를 허용하는 콜렉션 기반 오브젝트 스토리지
  • 자동 샤딩(Auto-sharding)을 이용한 수평적 확장
  • 경쟁이 없는 고성능의 동시성을 구현하는 데 필요한 제자리 쓰기(In-place update) 기능
  • 설치하지 않고도 MongoDB를 사용해 볼 수 있는 온라인 쉘
  • 발행되었거나 현재 작성 중인 여러 권의 책과 상세한 문서

MongoDB 설치

다행히도 MongoDB는 다양한 플랫폼에서 매우 간단하게 설치할 수 있다. 2진 배포판은 Windows, Mac OS X, Linux 및 Solaris에서 사용 가능하며 다른 시스템에서는 다양한 패키지 관리자가 쉬운 설치 및 설정 옵션을 제공한다. 자신이 있으면 직접 소스 코드를 컴파일해도 된다. 이 섹션에서는 Windows와 Mac OS X에서 MongoDB를 설치하고 프로세스를 Windows에서 서비스로 설정하거나 OS X에서 디먼으로 설정하는 방법을 배운다.

Windows에서 설치

Windows에서 MongoDB를 설치하는 과정은 매우 간단하다. 선호하는 웹 브라우저로 http://www.mongodb.org/downloads를 탐색하여 안정된 최신 프로덕션 릴리스(Windows용)를 다운로드한다. 64비트 버전을 권장하지만 이 버전은 Windows 운영 체제 64비트 버전을 사용 중인 경우에만 사용할 수 있다. 사용 중인 운영 체제의 버전이 불확실한 경우에는 32비트 버전을 사용한다.

zip 파일을 C:\drive에 추출하면 이름이 mongodb-win32-i386-1.6.4인 폴더가 새로 생긴다. 작업을 편하게 하려면 이 폴더의 이름을 mongo로 바꾼다. 다음에는 데이터 디렉토리를 작성해야 한다. Windows 탐색기에서 C:\drive의 루트로 이동하여 data라는 폴더를 새로 작성한다. 이 폴더 안에 db라는 폴더를 새로 작성한다.

그러면 MongoDB 서버를 시작할 수 있다. Windows 탐색기를 사용하여 C:\mongo\bin을 탐색하고 mongod.exe를 두 번 클릭한다. 열린 명령 프롬프트 창을 닫으면 MongoDB 서버가 중지된다. 따라서, MongoDB 서버를 Windows 제어인 서비스로 설정하는 것이 더 편리하다. 이제 이 작업을 수행하도록 하자.

Start>Run>을 선택하고 cmd를 입력한 후, OK를 클릭하여 명령행 프롬프트 창을 열고 목록 1에 있는 명령을 실행한다.


목록 1. MongoDB 서버를 서비스로 설정 
> cd \mongo\bin
> mongod --install --logpath c:\mongo\logs --logappend 
--bind_ip 127.0.0.1 --directoryperdb

목록 2에 있는 결과물이 표시된다.


목록 2. 성공적으로 작성된 서비스
all output going to c:\mongo\logs
Creating service MongoDB.
Service creation successful.
Service can be started from the command line via 'net start "MongoDB"'.

MongoDB를 서비스로 설치했으므로 다음 명령을 사용하여 MongoDB를 시작할 수 있다. > net start "MongoDB".

목록 3에 있는 결과물이 표시된다.


목록 3. 성공적으로 시작된 MongoDB
The Mongo DB service is starting.
The Mongo DB service was started successfully.

이제 MongoDB 쉘 클라이언트를 실행할 수 있다. 명령 프롬프트 창이 열리면 위치가 c:\mongo\bin 폴더인지 확인한 다음, >mongo 명령을 입력한다.

또는 Windows 탐색기에서 C:\mongo\bin으로 이동하여 mongo.exe를 두 번 클릭한다. 어떤 방법으로 쉘을 시작하든지 목록 4에 있는 것과 같은 프롬프트가 표시된다.


목록 4. 쉘 시작
MongoDB shell version: 1.8.1
connecting to: test
>

Mac OS X 시스템에서 MongoDB를 설정하는 경우가 아니면 이 섹션의 다음 부분을 건너뛰어 "시작하기"로 이동할 수 있다. 여기서는 쉘 클라이언트를 사용하여 MongoDB 서버와 상호 작용하는 방법을 배운다.

Mac OS X에서 설치

Mac OS X 64비트 버전을 사용 중이라고 가정하여 다음 단계에서는 MongoDB 64비트 OS X 2진 파일을 다운로드하여 추출한 후, 구성하여 시작하는 방법을 자세히 다룬다. 또한, MongoDB를 디먼으로 실행하는 방법을 살펴본다.

먼저, 터미널을 실행한다(Applications>Utilities>Terminal). 터미널 창에서 목록 5에 있는 명령을 실행한다.


목록 5. Mac OS X에서 MongoDB 설정
$ cd ~
$ curl http://fastdl.mongodb.org/osx/mongodb-osx-x86_64-1.6.4.tgz > mongo.tgz
$ tar xzf mongo.tgz
$ mv mongodb-osx-x86_64-1.8.1/ mongo
$ mkdir -p /data/db

이제 MongoDB가 설정되었으므로 사용할 차례이다. 진도를 나가기 전에 해당 경로에 MongoDB를 추가하는 것이 좋다. $ nano ~/.bash_profile 명령을 실행한다.

이 파일이 아직 존재하지 않을 수도 있다. 어떤 경우이든 다음 행(export PATH={$PATH}:~/mongo/bin)을 추가한다.

ctrl + O을 눌러서 파일을 저장한 후, 프롬프트에서 Enter를 누른다. 그런 다음, ctrl + X를 눌러서 nano를 종료한다. 이제, $ source ~/.bash_profile 명령을 사용하여 bash 프로파일을 다시 로드한다.

그러면 MongoDB를 시작할 준비가 된다. MongoDB를 시작하려면 $ mongod 명령을 실행한다.

이렇게 하면 MongoDB 데이터베이스 서버가 포그라운드 프로세스로 시작된다. MongoDB를 백그라운드에서 디먼 프로세스로 시작하고 싶은 경우에는 그 대신 $ sudo mongod --fork --logpath /var/log/mongodb.log --logappend 명령을 실행한다.

비밀번호를 입력하라는 메시지가 표시되면 이 프롬프트에서 Mac OS X 관리자 비밀번호를 입력한다.

MongoDB를 시작하는 방법에 관계없이 서버가 실행된다. MongoDB를 포그라운드에서 시작한 경우, 클라이언트를 시작하려면 별도의 Terminal 탭이나 창이 필요하다. 클라이언트를 시작하려면 $ mongo 명령을 사용한다.

목록 6에 있는 것과 같은 프롬프트가 표시된다.


목록 6. 클라이언트 시작
MongoDB shell version: 1.8.1
connecting to: test
> 

다음 섹션에서는 MongoDB 쉘을 사용하여 데이터베이스, 콜렉션 및 문서 등을 작성하는 방법을 배운다.

MongoDB 시작하기

MongoDB 배포판에 포함되어 있는 것은 데이터베이스를 완전히 제어할 수 있는 쉘 애플리케이션이다. 이 쉘을 사용하는 경우에는 서버측 Javascript 함수를 사용하여 데이터베이스, 콜렉션, 문서 및 인덱스를 작성하고 관리할 수 있다. 이 쉘을 사용하면 MongoDB를 신속하고 쉽게 실행할 수 있다. 이 섹션에서는 쉘을 시작하는 방법을 배우고 예제를 통해 기본적인 데이터 저장 및 검색을 수행할 수 있는 몇 가지 기본적인 명령을 살펴본다.

MongoDB 쉘

MongoDB 쉘 애플리케이션은 bin 폴더에 MongoDB 배포판과 함께 포함되어 있다. Windows에서는 이 쉘이 애플리케이션(mongo.exe)으로 존재한다. Windows 탐색기에서 이 프로그램을 두 번 클릭하면 쉘이 시작된다. 위에 있는 지시사항을 따라 MongoDB 디렉토리를 해당 경로에 추가했다고 가정하면 UNIX® 기반 운영 체제(Mac OS X 포함)에서는 터미널 창에서 mongo 명령을 실행하여 MongoDB 쉘을 시작할 수 있다.

먼저 쉘을 실행하면 목록 7에 있는 메시지가 표시된다.


목록 7. 쉘을 실행 한 후 표시되는 메시지
MongoDB shell version: 1.8.1
connecting to: test
> 

이제 로컬 MongoDB 서버(특히 "test" 데이터베이스)에 연결된다. 다음 섹션에서는 데이터베이스, 문서 및 콜렉션을 작성하는 방법을 배운다. 어떤 단계에서든 도움이 필요하면 Mongo 쉘 프롬프트에서 간단히 "help" 명령을 실행한다. 그림 1에는 help 명령을 실행했을 때 표시되는 일반적인 결과물이 표시되어 있다.


그림 1. Mongo 쉘에서 help 명령을 실행했을 때의 결과물
Mongo 쉘에서 help 명령을 실행했을 때의 결과물 

MongoDB 함수의 소스 코드를 알고 싶으면 쉘에서 해당 함수의 이름을 입력하기만 하면 해당하는 Javascript 소스가 표시된다. 예를 들면,connect를 입력하고 리턴 키를 누르면 MongoDB 데이터베이스에 연결하는 데 사용된 소스 코드가 표시된다.

데이터베이스 콜렉션 및 문서 작성

기본적으로 Mongo 쉘은 "test" 데이터베이스에 연결된다. 다른 데이터베이스로 전환하려면 "use dbname" 명령을 사용한다. 데이터베이스가 존재하지 않는 경우에는 데이터를 데이터베이스에 추가하는 즉시 MongoDB에서 데이터베이스가 작성된다. >use mymongo 명령을 사용하여 "mymongo" 데이터베이스로 전환한다.

쉘에서 switched to db mymongo 메시지가 리턴된다.

이 시점에서는 데이터베이스에 데이터가 없으므로 사실상 아직은 데이터베이스가 존재하지 않는다. MongoDB에서는 데이터가 콜렉션에 저장되므로 필요한 경우에는 문서를 분리할 수 있다. 문서를 작성하여 다음과 같이 새 콜렉션("colors")에 저장해 본다. > db.colors.save({name:"red",value:"FF0000"});.

다음과 같이 데이터베이스를 쿼리하여 문서가 저장되었는지 확인한다. > db.colors.find();.

다음과 같은 응답이 표시된다(_id 속성은 고유한 식별자로 결과마다 다를 수 있음). { "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "red", "value" : "FF0000" }.

MongoDB에서는 문서가 BSON(2진 JSON)으로 저장된다. Mongo 쉘을 사용하는 경우에는 JSON 형태의 구문을 사용하여 데이터를 삽입할 수 있으며 여기에서는 각 문서가 키/값 쌍으로 구성된 하나의 오브젝트이다. 이 예제에서는 값이 각각 red FF0000(표준 빨간색의 16진 표현)인 name  value 속성이 있는 문서를 작성했다.

알고 있을지 모르지만, colors 콜렉션을 사전 정의할 필요는 없었으며 이러한 작업은 save 함수를 사용하여 항목을 삽입할 때 자동으로 수행된다.

이 예제에서는 매우 간단한 문서를 작성했다. 그러나 사용된 JSON 형태의 구문은 더 복잡한 문서를 작성하는 데 사용될 수 있다. 구매 주문이나 송장을 표현하는 다음 JSON 문서를 생각해 보자(목록 8 참조).


목록 8. 간단한 문서 작성
{
    order_id: 109384,
    order_date: new Date("12/04/2010"),
    customer: {
        name: "Joe Bloggs",
        company: "XYZ Inc.",
        phone: "(555) 123-4567"
    },
    payment: {
        type: "Cash",
        amount: 4075.99,
        paid_in_full: true
    },
    items: [
        {
            sku: "ABC1200",
            description: "A sample product",
            quantity: 1,
            price_per_unit: 75.99,
        }, {
            sku: "XYZ3400",
            description: "An expensive product",
            quantity: 2,
            price_per_unit: 2000
        }
    ],
    cashier_id: 340582242
}

아는 바와 같이 이러한 문서에는 문자열, 정수, 부동수, 날짜, 오브젝트, 배열 등과 같은 다양한 데이터 유형을 저장할 수 있다. 목록 8에서는 주문 품목을 주문 문서에 직접 삽입하며, 이렇게 하면 나중에 문서를 쿼리할 때 이 정보를 더 빠르게 검색할 수 있다.

MongoDB 쉘은 Javascript를 사용하므로 데이터베이스와 상호 작용할 때 일반 Javascript 구문을 작성할 수 있다. 목록 9에서는 문자의 문자열 표현과 문자와 연관된 ASCII 코드가 각각 포함된 문자 문서 콜렉션을 작성한다.


목록 9. 문자 문서 콜렉션 작성
> var chars = "abcdefghijklmnopqrstuvwxyz"
> for(var i =0; i<chars.length; i++) {    
... var char = chars.substr(i, 1);          
... var doc = {char:char, code: char.charCodeAt(0)};
... db.alphabet.save(doc);
... }

이 루프에서는 각 알파벳 소문자에 해당하는 문서가 26개 작성되며 각 문서에는 문자 자체와 문자의 ASCII 코드가 포함되어 있다. 다음 섹션에서는 다양한 방식으로 이 데이터를 검색하는 방법을 살펴본다.

데이터 검색하기

마지막 섹션에서는 MongoDB 데이터베이스에 데이터를 삽입하는 방법을 배울 뿐만 아니라 가장 기본적인 데이터 검색 함수인 find를 사용하는 방법을 배운다. 먼저, 이전 섹션의 마지막 부분에서 작성한 알파벳 콜렉션을 대상으로 다음과 같이 find 명령을 사용하자.db.alphabet.find();.

이렇게 하면 목록 10과 같은 응답이 생성된다.


목록 10. 생성된 응답
> db.alphabet.find()
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec90"), "char" : "e", "code" : 101 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f", "code" : 102 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g", "code" : 103 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h", "code" : 104 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i", "code" : 105 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec95"), "char" : "j", "code" : 106 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec96"), "char" : "k", "code" : 107 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec97"), "char" : "l", "code" : 108 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec98"), "char" : "m", "code" : 109 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec99"), "char" : "n", "code" : 110 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9a"), "char" : "o", "code" : 111 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9b"), "char" : "p", "code" : 112 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9c"), "char" : "q", "code" : 113 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9d"), "char" : "r", "code" : 114 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9e"), "char" : "s", "code" : 115 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec9f"), "char" : "t", "code" : 116 }
has more
> 

기본적으로 find() 함수는 콜렉션에 있는 모든 문서를 검색하지만, 처음 20개의 문서만 표시한다. it 명령을 입력하면 나머지 문서 6개가 검색된다(목록 11 참조).


목록 11. 나머지 문서 6개 검색
> it
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca0"), "char" : "u", "code" : 117 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca1"), "char" : "v", "code" : 118 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca2"), "char" : "w", "code" : 119 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca3"), "char" : "x", "code" : 120 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca4"), "char" : "y", "code" : 121 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca5"), "char" : "z", "code" : 122 }
> 

사실상 find() 함수는 쿼리 결과 세트에 커서를 리턴하며, 이 경우에는 모든 문서를 검색한다. 이것을 변수에 지정하지 않거나 더 이상의 함수가 수행되지 않으면 기본적으로 샘플 결과 세트가 화면에 표시된다. >db.alphabet.find().forEach(printjson); 명령을 사용하여 모든 결과 세트를 표시할 수도 있다.

이렇게 하면 서브세트가 표시되는 대신 모든 레코드가 결과 세트로 표시된다. 다음 섹션에서는 커서와 쿼리를 사용하여 데이터를 필터링하는 방법을 자세히 본다.

데이터 쿼리

MongoDB의 가장 큰 강점 중 하나는 비록 테이블 대신 BSON 문서를 필터링하고 리턴하기는 해도 기존의 관계형 데이터베이스와 거의 같은 방식으로 작동하는 임시 쿼리를 강력하게 지원한다는 점이다. 이러한 방식이 SQL 개발자들이 이해하는 데 어려울 수도 있는 다른 문서 저장소와 MongoDB의 차이점이다. MongoDB를 사용하면 비교적 복잡한 SQL 쿼리를 Javascript 함수 호출로 쉽게 변환할 수 있다. 이번 섹션에서는 MongoDB에서 데이터를 쿼리할 때 사용되는 다양한 함수와 DB2, MySQL 또는 Oracle의 like에서와 같이 인덱스를 설정하여 쿼리를 최적화하는 방법을 배운다.

기본 쿼리

이전 섹션에서는 find 함수를 사용하여 모든 문서를 검색하는 방법을 배웠다. find 함수는 리턴된 결과를 필터링할 수 있는 일련의 인수를 받는다. 예를 들면, >db.alphabet.find({char: "o"}); 명령을 사용하여, 앞서 작성한 알파벳 콜렉션에서 "char" 속성값이 "q"인 모든 레코드를 찾을 수 있다.

이 명령은 { "_id" : ObjectId("4cfa4adf528bad4e29beec9a"), "char" : "o", "code" : 111 } 응답을 리턴한다.

코드가 100 이하인 모든 문자를 리턴하려면 다음 명령을 사용한다. >db.alphabet.find({code:{$lte:100}});.

예상하는 바와 같이 이 명령은 목록 12와 같은 결과를 리턴한다.


목록 12. 결과
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 }

MongoDB는 다음과 같은 다양한 조건부 연산자를 지원한다.

  • $lt(미만)
  • $lte(이하)
  • $gt(초과)
  • $gte(이상)
  • $all(배열에 있는 모든 값과 일치)
  • $exists(필드의 존재 여부 확인)
  • $mod(모듈)
  • $ne(같지 않음)
  • $in(배열에 있는 하나 이상의 값과 일치)
  • $nin(배열에 있는 0 값과 일치)
  • $or(쿼리 중 하나와 일치)
  • $nor(쿼리 중 어느 것과도 일치하지 않음)
  • $size(정의된 요소 수가 있는 배열과 일치)
  • $type(지정된 BSON 데이터 유형의 값과 일치)
  • $not(같지 않음)

이러한 모든 연산자를 자세히 확인하려면 MongoDB 문서를 참조한다(링크는 참고자료 참조).

find 함수의 두 번째 인수를 사용하여 쿼리에서 리턴되는 필드를 제한할 수 있다. 예를 들면, 다음 쿼리는 코드 값이 102 ~ 105 범위 안에 있는 모든 문서의 char 속성만을 리턴한다. > db.alphabet.find({code:{$in:[102,103,104,105]}}, {char: 1});.

이 쿼리의 결과는 목록 13과 같다.


목록 13. 결과
{ "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f" }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g" }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h" }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i" }

다음 섹션에서는 인덱스를 작성하여 쿼리 속도를 높이는 방법을 배운다.

인덱싱

MongoDB 인덱스는 관계형 데이터베이스 인덱스와 매우 비슷하다. 모든 속성에 인덱스를 삽입할 수 있다. 이외에도 인덱스화된 필드는 모든 데이터 유형(오브젝트 또는 배열 포함)이 될 수 있다. RDBMS 인덱스와 마찬가지로 다중 속성과 고유 인덱스를 사용하여 복합 인덱스를 작성할 수 있으며 이렇게 하면 값이 중복되지 않도록 할 수 있다.

기본 인덱스를 작성하려면 ensureIndex 함수를 사용한다. 이제 알파벳 콜렉션의 code char 속성을 대상으로 인덱스를 작성하자(목록 14참조).


목록 14. 인덱스 작성
> db.alphabet.ensureIndex({code: 1});
> db.alphabet.ensureIndex({char: 1});

dropIndex와 dropIndexes 함수를 사용하여 인덱스를 삭제할 수 있다. 자세한 내용은 MongoDB 문서를 참조한다.

정렬

결과 세트를 정렬하려면 해당 커서에 sort 함수를 적용한다. 알파벳 콜렉션은 이미 code와 char 속성으로 오름차순으로 정렬되어 있으므로 서브세트를 다시 code 속성으로 오름차순으로 정렬하자. > db.alphabet.find({code: {$gte: 118}}).sort({code: 0});.

이 쿼리는 목록 15와 같은 결과를 리턴한다.


목록 15. 결과
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca5"), "char" : "z", "code" : 122 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca4"), "char" : "y", "code" : 121 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca3"), "char" : "x", "code" : 120 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca2"), "char" : "w", "code" : 119 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beeca1"), "char" : "v", "code" : 118 }

이전 명령에서 sort 함수에 {code: 1} 인수를 제공하면 결과가 오름차순으로 정렬된다. 쿼리의 성능을 강화하려면 사용할 데이터를 정렬할 모든 속성에 인덱스를 추가해야 한다.

SKIP과 LIMIT를 사용하여 결과를 페이지로 나누기

데이터 결과 세트를 처리할 때는 아마도 결과를 페이지로 나누어서 웹 페이지에 표시하기 위해 한 번에 하나의 서브세트만 검색하고자 할 경우도 있다. MySQL에서는 LIMIT 키워드를 사용하여 이러한 작업을 수행한다. MongoDB에서는 skip과 limit 함수를 사용하여 이 기능을 쉽게 복제할 수 있다. 알파벳 콜렉션에서 처음 5개 문서를 리턴하려면 다음 조작을 수행한다. > db.alphabet.find().limit(5);.

이 조작은 목록 16과 같은 결과를 리턴한다.


목록 16. 결과
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8c"), "char" : "a", "code" : 97 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8d"), "char" : "b", "code" : 98 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8e"), "char" : "c", "code" : 99 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec8f"), "char" : "d", "code" : 100 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec90"), "char" : "e", "code" : 101 }

다음 페이지를 얻으려면 다음 명령을 사용한다. > db.alphabet.find().skip(5).limit(5);.

목록 17에서 알 수 있는 바와 같이 이 명령은 다음 5개 레코드를 페치한다.


목록 17. 다음 5개 레코드 페치
{ "_id" : ObjectId("4cfa4adf528bad4e29beec91"), "char" : "f", "code" : 102 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec92"), "char" : "g", "code" : 103 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec93"), "char" : "h", "code" : 104 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec94"), "char" : "i", "code" : 105 }
{ "_id" : ObjectId("4cfa4adf528bad4e29beec95"), "char" : "j", "code" : 106 }

group 함수와 수집

MongoDB의 쿼리 엔진을 이용하면 해당 데이터에 수집 및 그룹 함수를 매우 간단하게 적용할 수 있다. 이러한 기능은 다른 데이터베이스의 해당 SQL 기능과 비슷하다. 이론의 여지가 있지만, 가장 널리 사용되는 함수는 count() 함수이다. > db.alphabet.find().count();.

이 명령은 26을 리턴한다. 필터링된 쿼리를 다음과 같이 쉽게 계수할 수 있다. > db.alphabet.find({code: {$gte: 105}}).count();.

위에 있는 명령문은 18을 리턴한다.

또 다른 유용한 수집 함수는 distinct이다. 이 함수는 고유한 속성값 세트를 리턴하기 위해 사용된다. 알파벳 콜렉션은 모든 데이터가 고유하기 때문에 예제로서 적합하지 않다. 그러므로 이 기사의 앞 부분에서 작성한 colors 콜렉션에 레코드 두 개를 추가한다(목록 18 참조).


목록 18. color 콜렉션에 레코드 추가
> db.colors.save({name:"white",value:"FFFFFF"});
> db.colors.save({name:"red",value:"FF0000"});  
> db.colors.find();

colors 콜렉션을 삭제하지 않았다고 가정하면 목록 19와 같은 응답이 표시된다.


목록 19. 응답
{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "red", "value" : "FF0000" }
{ "_id" : ObjectId("4cfa5830528bad4e29beeca8"), "name" : "white", "value" : "FFFFFF" }
{ "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" }

아는 바와 같이 이 콜렉션에는 분명히 빨간색 문서가 두 개 있다. 이제, distinct 함수를 사용하여 이 콜렉션에서 고유한 name 속성값을 가져온다. > db.colors.distinct("name");.

이 명령은 [ "red", "white" ]를 리턴한다.

다른 쿼리 함수를 수행하므로 커서나 결과 세트에 대해서는 distinct 함수를 수행하지 않고 콜렉션을 대상으로 직접 distinct 함수를 수행한다. 또한, 이 함수가 문서 세트를 리턴하지 않고 값으로 구성된 배열을 리턴한다는 점을 알게 된다.

MongoDB는 SQL의 GROUP BY 표현식으로 하는 것과 같은 조치를 수행하는 데 필요한 group 함수를 제공한다. group 함수는 복잡하므로 여기에서는 간단한 예제만 살펴보도록 한다. 예를 들면, 이름 값으로 그룹화된 문서의 수를 계수한다고 가정한다. SQL에서는 이 표현식을 다음과 같이 정의할 수 있다. SELECT name, COUNT(*) FROM colors GROUP BY name;.

MongoDB에서 이 쿼리를 수행하려면 목록 20에 있는 명령을 사용해야 한다.


목록 20. group 함수 사용
> db.colors.group(
... {key: {name: true},
... cond: {},
... initial: {count: 0},                                  
... reduce: function(doc, out) { out.count++; }
... });

이 코드는 목록 21과 같은 결과를 생성한다.


목록 21. 결과
[
    {
        "name" : "red",
        "count" : 2
    },
    {
        "name" : "white",
        "count" : 1
    }
]

고급 수집 기능을 수행해야 하거나 대용량 데이터 세트를 사용해야 하는 경우, MongoDB에는 이러한 기능을 수행할 수 있는 map/reduce 구현이 포함되어 있다. 위에서 언급한 group 함수는 공유된 MongoDB 설정에서는 작동하지 않으므로 샤딩을 사용할 경우에는 group 함수 대신map/reduce를 사용해야 한다.

기존 데이터 업데이트

MongoDB 쉘에서는 문서를 업데이트하기가 매우 쉽다. 앞서 작성한 colors 콜렉션에는 red에 해당하는 레코드가 두 개 있었다. 이 레코드 중 하나를 취하여 값 속성이 000000(검정색의 16진 값)인 black으로 변경한다고 가정한다. 먼저, findOne 함수를 사용하여 값이 red인 단일 항목을 검색하고 필요에 따라 그 특성을 변경하고 해당 문서를 다시 데이터베이스에 저장할 수 있다.

이름이 red인 단일 문서를 가져와서 다음과 같이 blackDoc 변수에 저장한다. > var blackDoc = db.colors.findOne({name: "red"});.

다음에는 점 표기법을 사용하여 문서의 특성을 변경한다(목록 22 참조).


목록 22. 문서의 특성 변경

> blackDoc.name = "black";
> blackDoc.value = "000000";

문서를 저장하기 전에 다음과 같이 문서가 올바른지 확인한다. (문서에는 _id 속성이 있어야 한다. 그렇지 않으면 문서가 red 레코드를 덮어서 저장되지 않고 새 레코드로 삽입된다.) > printjson(blackDoc);

목록 23과 같은 결과가 리턴되면 준비가 된 것이다.


목록 23. 결과
{
    "_id" : ObjectId("4cfa43ff528bad4e29beec57"),
    "name" : "black",
    "value" : "000000"
}

마지막으로 save 함수를 사용하여 문서를 다시 데이터베이스의 colors 콜렉션에 저장한다. > db.colors.save(blackDoc);.

이제 find 함수를 사용하여 콜렉션이 올바른지 확인할 수 있다. > db.colors.find();.

그러면 목록 24와 같은 결과가 리턴된다. 레코드가 4개이면 잘못된 것이다.


목록 24. 결과
{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "black", "value" : "000000" }
{ "_id" : ObjectId("4cfa5830528bad4e29beeca8"), "name" : "white", "value" : "FFFFFF" }
{ "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" }

Mongo 쉘 외부에서는 애플리케이션에서 update 함수를 사용하여 기존 데이터를 변경한다. update 함수에 대한 자세한 정보는 MongoDB 문서를 참조한다.

데이터 삭제

MongoDB에서 데이터를 삭제하려면 remove 함수를 사용한다. 이는 MongoDB 쉘 프로그램에도 적용되며, 일부 드라이버가 delete 함수를 구현할 수도 있고 그렇지 않을 수도 있다. 필요한 경우에는 특정 구현에 대한 문서를 확인한다.

remove 함수는 find 함수와 비슷하게 작동한다. colors 콜렉션에서 이름이 white인 문서와 일치하는 문서를 제거하려면 다음 명령을 사용한다. > db.colors.remove({name:"white"});.

그런 다음, 다음과 같이 이 문서가 제거되었는지 확인한다. > db.colors.find();.

모든 것이 제대로 되면 문서 두 개만 표시된다(목록 25 참조).


목록 25. 데이터 삭제
{ "_id" : ObjectId("4cfa43ff528bad4e29beec57"), "name" : "black", "value" : "000000" }
{ "_id" : ObjectId("4cfa5839528bad4e29beeca9"), "name" : "red", "value" : "FF0000" }

콜렉션에서 모든 문서를 제거하려면 다음과 같이 명령에서 필터를 생략한다. > db.colors.remove();.

이제는 다음과 같이 find 함수를 사용하려고 해도 응답이 표시되지 않으며 이는 결과 세트가 없다는 것을 의미한다. > db.colors.find();.

변수에 문서를 저장한 경우에는 이 문서를 remove 함수에 전달하여 문서를 삭제할 수 있지만, 이렇게 하는 것은 효과적인 방법이 아니다. 그 대신 이 문서의 _id 속성을 찾아서 remove 함수에 전달하는 것이 더 나은 방법이다.

콜렉션을 삭제하려면 다음 명령을 사용한다. > db.colors.drop();.

이 명령은 true를 리턴한다.

이제 show collections 명령을 사용하여 실제로 콜렉션이 삭제되었는지 확인한다. 그러면 목록 26과 같은 결과가 표시된다.


목록 26. show collections 명령 사용
alphabet
system.indexes

마지막으로 전체 데이터베이스를 제거할 경우에는 다음 명령을 수행한다. > db.dropDatabase();.

이 명령은 현재 선택된 데이터베이스를 삭제한다. 다음과 같은 결과가 표시된다. { "dropped" : "mymongo", "ok" : 1 }.

show dbs 명령을 사용하여 사용 가능한 데이터베이스 목록을 확인한다. mymongo는 이 목록에 표시되지 않는다.

도구와 기타 기능

MongoDB에는 데이터베이스를 관리하는 데 필요한 일련의 유용한 유틸리티가 포함되어 있다. 또한, MongoDB에는 보고나 백업을 위해 데이터를 가져오거나 내보낼 수 있는 다양한 수단이 있다. 이번 섹션에서는 파일을 JSON 형식으로 가져오거나 내보내는 방법과 복구를 하는 데 더욱 효과적인 핫 백업 파일을 작성하는 방법을 알아본다. 또한, map/reduce 함수를 복잡한 데이터 수집에 필요한 Mongo의 일반 쿼리 함수의 대체 수단으로 사용하는 방법을 배운다.

데이터 가져오기 및 내보내기

MongoDB의 bin 디렉토리에는 다양한 형식으로 데이터를 가져오고 내보낼 수 있는 일련의 유틸리티가 있다. mongoimport 유틸리티를 이용하면 각 행에 JSON, CSV 또는 TSV 형식의 문서가 포함되어 있는 파일을 제공하고 이러한 각 문서를 MongoDB 데이터베이스에 삽입할 수 있다. MongoDB에서는 BSON 형식을 사용하므로 JSON 문서를 가져올 경우, 일반 JSON으로는 사용 불가능한, BSON의 추가 데이터 형식을 이용하려면 수정자 정보를 일부 제공해야 한다.

mongoexport 유틸리티를 이용하면 JSON이나 CSV 형식으로 표현된, MongoDB 데이터베이스의 모든 문서가 있는 파일 결과물을 생성할 수 있다. 이 유틸리티는 애플리케이션에서 JSON이나 CSV 데이터를 입력으로 받아서 보고서를 생성하는 데 유용하다. CSV 파일을 생성하려면 결과 파일에 표시되는 순서에 해당 필드를 제공해야 한다.

데이터베이스 백업 및 복원

mongoimport 및 mongoexport 유틸리티는 MongoDB에서 데이터를 가져와서 다른 애플리케이션에서 사용하거나 JSON 또는 CSV 데이터를 사용 가능하게 할 수 있는 다른 애플리케이션에서 데이터를 가져오는 데 유용하다. 그러나 이러한 유틸리티는 MongoDB 데이터베이스를 주기적으로 백업하거나 복원하는 데는 사용되지 않는다. MongoDB에서는 JSON이나 CSV 대신 BSON을 사용하기 때문에 이러한 형식으로 데이터를 가져올 경우에는 데이터 유형을 유지하기가 어렵다.

적당한 백업 및 복원 기능을 제공하기 위해 MongoDB는 두 가지 유틸리티(mongodump 및 mongorestore)를 제공한다. mongodump는 데이터베이스의 2진 백업 파일을 생성하며 mongorestore는 이 파일을 읽어서 이 파일을 사용하는 데이터베이스를 복원하고 필요에 따라 자동으로 인덱스를 작성한다(백업 디렉토리에서 system.indexes.bson 파일을 제거하지 않는 한).

관리 유틸리티

또한, MongoDB는 웹 기반 진단 인터페이스를 제공하며, MongoDB가 기본값으로 구성된 경우에는 이 인터페이스를http://localhost:28017/ URL에서 이용할 수 있다. 이 화면은 그림 2에 있는 스크린샷과 같다.


그림 2. MongoDB의 진단 인터페이스
MongoDB의 진단 인터페이스 

기타 관리 정보를 얻으려면 MongoDB 쉘에서 다음 명령을 실행한다.

  • db.serverStatus();
  • db.stats();

MongoDB 서버가 파손되는 경우에는 데이터베이스를 복구하여 손상이 없는지 확인하고 데이터 압축을 일부 수행한다. OS 명령행에서 mongod --repair를 실행하거나 MongoDB 쉘에서 db.repairDatabase(); 명령을 사용하여 복구를 실행할 수 있다. 후자는 데이터베이스 레벨에 따라 실행되므로 해당 서버에서 각 데이터베이스를 대상으로 이 명령을 실행해야 한다.

또한, 유효성 검증 함수를 사용하여 콜렉션 데이터의 유효성을 검증할 수 있다. contacts라는 콜렉션이 있는 경우에는db.contacts.validate(); 명령을 사용하여 콜렉션의 유효성을 검증할 수 있다.

이외에도 MongoDB에는 DBA에게 도움이 되는 기능이 많이 있다. 이외에도 다양한 써드파티 관리 도구와 인터페이스를 사용할 수 있다. 자세한 정보는 MongoDB 문서를 참조한다.

map/reduce

뷰 엔진은 기본적으로 map/reduce 함수를 사용하여 데이터를 필터링하고 수집하므로 이전에 CouchDB 데이터베이스를 사용한 적이 있으면map/reduce 함수에 익숙할 것이다. 그러나 MongoDB에서는 이렇게 하지 않으며 간단한 쿼리와 필터링 및 수집 기능은 map/reduce 함수에 의존하지 않는다. 그러나 MongoDB는 대용량 데이터 세트를 수집하는 데 사용할 수 있는 map/reduce 구현을 제공한다.

map/reduce는 그 자체로도 하나의 기사가 될 수 있다. 그러므로 MongoDB의 map/reduce 구현에 대한 자세한 정보는 MongoDB 문서를 참조한다(링크는 참고자료 참조).

MongoDB 확장

키/값 저장소와 문서 지향 데이터베이스가 최근에 널리 사용되는 기본적인 이유는 확장성이 우수하고 메모리를 적게 사용한다는 데 있다. 이러한 점을 활용하기 위해 MongoDB는 이번 섹션에서 배우게 될 샤딩과 복제 개념에 의존한다. 이외에도 GridFS를 사용하여 대용량 파일을 MongoDB에 저장하는 방법을 배운다. 마지막에는 쿼리를 프로파일링하여 데이터베이스의 성능을 최적화하는 방법을 배운다.

샤딩

데이터베이스 인프라의 핵심 부분은 확장성에 있다. MongoDB 구현은 자동 샤딩 메커니즘을 사용하여 수평으로 확장되며, 이 메커니즘을 이용하면 자동 로드 밸런싱, 단일 장애 지점 불허 및 자동 장애 복구 기능과 더불어 MongoDB 구성을 수천 개의 노드로 확장할 수 있다. MongoDB 클러스터에 시스템을 새로 추가하는 것도 매우 간단하다.

MongoDB의 자동 샤딩 기능의 장점은 애플리케이션 코드를 거의 변경하지 않고도 단일 서버에서 샤딩된 클러스터로 이동하기가 매우 간단하다. 자동 샤딩이 작동하는 과정과 자동 샤딩을 구현하는 방법과 관련된 자세한 문서는 MongoDB 문서를 참조한다.

복제

MongoDB는 장애 복구와 중복을 구현하기 위해 MySQL과 마찬가지로 마스터-슬레이브 구성의 복제 기능을 제공하며, 이 기능은 노드 간의 일관성을 높은 수준으로 보장한다. 또는 MongoDB에서는 복제 세트를 사용하여 언제든지 노드를 기본 노드로 정의할 수 있으며 장애가 발생했을 때는 또 다른 노드를 기본 노드로 대체할 수 있다.

복제를 기본으로 하여 확장을 하는 CouchDB와 달리, MongoDB에서는 슬레이브 노드를 중복 복제본으로 사용하여 고가용성을 보장하기 위해 주로 복제를 사용한다.

MongoDB 복제에 대한 자세한 정보는 MongoDB 문서를 참조한다(링크는 참고자료 참조).

GridFS를 사용하는 대용량 파일 스토리지

MongoDB 데이터베이스는 BSON 문서로 데이터를 저장한다. 그러나 BSON 문서의 최대 크기는 4MB이기 때문에 BSON 문서로 대용량 파일이나 오브젝트를 저장하는 것은 적합하지 않다. MongoDB에서는 GridFS 스펙을 사용하여 파일을 작은 청크로 나누고 다수의 문서에 분배하여 대용량 파일을 저장한다.

표준 MongoDB 배포판에는 GridFS 파일을 로컬 파일 시스템에 추가하거나 로컬 파일 시스템에서 GridFS 파일을 검색하는 데 필요한 명령행 유틸리티가 들어 있다. 이외에도 모든 공식 MongoDB API 드라이버에는 GridFS에 대한 지원이 포함되어 있다. 자세한 내용은 MongoDB 문서를 참조한다(참고자료 참조).

결론

이 기사에서는 MongoDB 데이터베이스 관리 시스템을 배웠으며 MongoDB가 DBMS 시장의 인기 있는 NoSQL 섹션에서 가장 빠르게 성장하는 옵션 중 하나인 이유를 알아 보았다. 또한, 기존의 RDBMS에 비해 문서 지향 데이터베이스를 선택하는 이유와 MongoDB에서 제공하는 여러 가지 우수한 기능을 배웠다. 더불어 MongoDB를 설치하는 방법과 MongoDB를 사용하여 데이터를 저장하고 검색하는 방법을 배웠을 뿐만 아니라 MongoDB에서 제공하는 다양한 도구와 확장성 옵션을 알아 보았다.


참고자료

교육

  • 공식 MongoDB 사이트를 방문하자. 

  • Wikipedia의 MongoDB 목록을 읽어보자. 

  • 공식 MongoDB 문서에 액세스할 수 있다. 

  • MongoDB map/reduce 함수를 자세히 배우자. 

  • MongoDB Cookbook에는 MongoDB를 사용하는 일반적인 방법이 자세히 설명되어 있다. 

  • Twitter의 MongoDB 페이지를 팔로우하자. 

  • developerWorks에 있는 "An introduction to MongoDB" 데모를 보자. 

  • developerWorks의 지식 경로를 통해 NoSQL을 사용하는 방법과 대용량 데이터를 분석하는 방법을 배우자. 

  • 한 회사에서 MySQL을 MongoDB로 전환한 방법을 확인하려면 Notes from a production MongoDB deployment를 읽어 본다. 

  • Collective Idea가 어떻게 전환했는지 배우려면 Reflections on MongoDB을 읽어보자. 

  • Wordnik이 어떻게 전환했는지 배우려면 12 Months with MongoDB 블로그를 읽어보자. 

  • Eltot Horowitz(MongoDB를 후원하는 회사인 10gen의 CTO)의 MongoDB 관련 팟캐스트를 들어보자. 

  • 10gen에서는 확장 가능한 고성능 문서 지향 오픈 소스 데이터베이스인 MongoDB를 개발하고 지원한다. 

  • Java development 2.0: MongoDB: A NoSQL datastore with (all the right) RDBMS moves(Andrew Glover, developerWorks, 2010년 9월): MongoDB의 사용자 정의 API, 대화식 쉘, RDBMS 스타일 동적 쿼리 및 빠르고 쉬운 MapReduce 계산에 관해 자세히 배우자. 

  • Exploring CouchDB(Joe Lennon, developerWorks, 2009년 3월): Apache의 오픈 소스 CouchDB는 스키마 없는 문서 지향 데이터베이스 모델로 부르는 것으로 데이터를 저장하는 새로운 방법을 제공한다. CouchDB는 관계형 모델의 고도로 구조화된 데이터 스토리지 대신, 반구조화된 문서로부터 구조화된 수집 및 보고 결과를 생성하는 데 필요한 Javascript 기반 뷰 모델을 사용하여 반구조화된 형식으로 데이터를 저장한다. 

  • 관심 이벤트: IBM 오픈 소스 개발자에게 유익한 컨퍼런스, 기술 박람회, 웹 캐스트 및 기타 행사를 확인하고 참여하자. 

  • developerWorks 오픈 소스 영역: 오픈 소스 기술을 사용하여 개발하고 이러한 기술을 IBM 제품과 함께 사용하는 데 도움이 되는 광범위한 사용법 정보, 도구 및 프로젝트 업데이트를 찾아보자. 

제품 및 기술

  • MongoDB를 다운로드하자. 

  • IBM 시험판 소프트웨어: 다운로드하거나 DVD로 이용할 수 있는 IBM 시험판 소프트웨어를 사용하여 차기 오픈 소스 개발 프로젝트를 강화하자. 

토론

  • developerWorks 커뮤니티: 개발자가 운영하고 있는 블로그, 포럼, 그룹 및 위키를 살펴보면서 다른 developerWorks 사용자와 의견을 나눌 수 있다. developerWorks 커뮤니티에서 Real world open source 그룹을 빌드하는 데 도움을 주자. 

필자소개

Joe Lennon

Joe Lennon은 소프트웨어 개발자로 24살이며 아일랜드 코크에 살고 있다. Joe Lennon은 Beginning CouchDB의 저자이며, 이 책은 Apress에서 출간될 예정이다. 그는 여러 개의 기술 관련 기사와 튜토리얼을 IBM developerWorks에 기고했다. 한가로운 때에는 축구를 하거나 가젯을 조작하며 Xbox 360 게이머 점수를 높이기 위해 노력한다. 그의 웹 사이트 주소는www.joelennon.ie이다.


출처 - http://www.ibm.com/developerworks/kr/library/os-mongodb4/index.html



'DB > MongoDB' 카테고리의 다른 글

mongodb - mongod.conf(web interface enable)  (0) 2013.05.19
mongo - 보안 및 계정 관리  (0) 2013.04.30
mongodb - Hadoop과 연동한 구축사례  (0) 2013.04.29
mongodb - 고려 사항  (0) 2013.04.29
mongodb wiki intro  (0) 2013.01.07
Posted by linuxism
,

mongodb wiki intro

DB/MongoDB 2013. 1. 7. 09:31


MongoDB
MongoDB Logo.png
Developer(s)10gen
Initial release2009
Stable release2.2.2 / 27 November 2012; 34 days ago
Development statusActive
Written inC++
Operating systemCross-platform
Available inEnglish
TypeDocument-oriented database
LicenseGNU AGPL v3.0 (drivers: Apache license)
Websitewww.mongodb.org


MongoDB (from "humongous") is an open source document-oriented database system developed and supported by 10gen. It is part of the NoSQLfamily of database systems. Instead of storing data in tables as is done in a "classical" relational database, MongoDB stores structured data as JSON-like documents with dynamic schemas (MongoDB calls the format BSON), making the integration of data in certain types of applications easier and faster.

10gen began Development of MongoDB in October 2007. The database is used by MTV Networks,[1] Craigslist,[2] Foursquare[3] and UIDAI Aadhaar. MongoDB is the most popular NoSQL database management system.[4]

Binaries are available for Windows, Linux, OS X, and Solaris.

Contents

  [hide

[edit]History

Development of MongoDB began at 10gen in 2007, when the company was building a platform as a service similar to Windows Azure or Google App Engine.[5] In 2009, MongoDB was open sourced as a stand-alone product[6] with an AGPL license.

In March 2010, from version 1.4, MongoDB has been considered production ready.[7]

The latest stable version, 2.2, was released in August 2012.

[edit]Licensing and support

MongoDB is available for free under the GNU Affero General Public License.[6] The language drivers are available under an Apache License. In addition, 10gen offers commercial licenses for MongoDB.[8]

[edit]Main features

The following is a brief summary of some of the main features:

Ad hoc queries
MongoDB supports search by field, range queries, regular expression searches. Queries can return specific fields of documents and also include user-defined JavaScript functions.
Indexing
Any field in a MongoDB document can be indexed (indices in MongoDB are conceptually similar to those in RDBMSes). Secondary indices are also available.
Replication
MongoDB supports master-slave replication. A master can perform reads and writes. A slave copies data from the master and can only be used for reads or backup (not writes). The slaves have the ability to select a new master if the current one goes down.
Load balancing
MongoDB scales horizontally using sharding.[9] The developer chooses a shard key, which determines how the data in a collection will be distributed. The data is split into ranges (based on the shard key) and distributed across multiple shards. (A shard is a master with one or more slaves.)
MongoDB can run over multiple servers, balancing the load and/or duplicating data to keep the system up and running in case of hardware failure. Automatic configuration is easy to deploy and new machines can be added to a running database.
File storage
MongoDB could be used as a file system, taking advantage of load balancing and data replication features over multiple machines for storing files.
This function, called GridFS,[10] is included with MongoDB drivers and available with no difficulty for development languages (see "Language Support" for a list of supported languages). MongoDB exposes functions for file manipulation and content to developers. GridFS is used, for example, in plugins for NGINX.[11] and lighttpd[12]
In a multi-machine MongoDB system, files can be distributed and copied multiple times between machines transparently, thus effectively creating a load balanced and fault tolerant system.
Aggregation
MapReduce can be used for batch processing of data and aggregation operations. The aggregation framework enables users to obtain the kind of results for which the SQL GROUP BY clause is used.
Server-side JavaScript execution
JavaScript can be used in queries, aggregation functions (such as MapReduce), are sent directly to the database to be executed.
Capped collections
MongoDB supports fixed-size collections called capped collections. This type of collection maintains insertion order and, once the specified size has been reached, behaves like a circular queue.

For further information on the points listed look up the MongoDB Developer Manual

[edit]Use cases and production deployments

MongoDB is well suited for the following cases[13]:

  • Archiving and event logging
  • Document and Content Management Systems. As a document-oriented (JSON) database, MongoDB's flexible schemas are a good fit for this.
  • E-commerce. Several sites are using MongoDB as the core of their ecommerce infrastructure (often in combination with an RDBMS for the final order processing and accounting).
  • Gaming. High performance small read/writes are a good fit for MongoDB; also for certain games geospatial indexes can be helpful.
  • High volume problems. Problems where a traditional DBMS might be too expensive for the data in question. In many cases developers would traditionally write custom code to a filesystem instead using flat files or other methodologies.
  • Mobile. Specifically, the server-side infrastructure of mobile systems. Geospatial indexes are key here.
  • Operational data store of a web site. MongoDB is very good at real-time inserts, updates, and queries. Scalability and replication are provided which are necessary functions for large web sites' real-time data stores. Specific web use case examples:
    • content management
    • comment storage, management, voting
    • user registration, profile, session data
  • Projects using iterative/agile development methodologies. Mongo's BSON data format makes it very easy to store and retrieve data in a document-style / "schemaless" format. Addition of new properties to existing objects is easy and does not generally require blocking "ALTER TABLE" style operations.
  • Real-time stats/analytics

[edit]Enterprises that use MongoDB

Many enterprises use and have production deployments of MongoDB[14]

[edit]Data manipulation: collections and documents

MongoDB stores structured data as JSON-like documents, using dynamic schemas (called BSON), rather than predefined schemas.

An element of data is called a document, and documents are stored in collections. One collection may have any number of documents.

Compared to relational databases, we could say collections are like tables, and documents are like records. But there is one big difference: every record in a table has the same fields (with, usually, differing values) in the same order, while each document in a collection can have completely different fields from the other documents. The only schema requirement mongo places on documents (aside from size limits) is that they must contain an '_id' field with a unique, non-array value.

A typical table in a relational database, accessible by SQL, could be depicted like this:

Last NameFirst NameDate of Birth
DUMONTJean01-22-1963
PELLERINFranck09-19-1983
GANNONDustin11-12-1982
Every record in an SQL-accessible table has the same fields, in the same order.

In contrast, a typical MongoDB collection would look like this:

{
    "_id": ObjectId("4efa8d2b7d284dad101e4bc9"),
    "Last Name": "DUMONT",
    "First Name": "Jean",
    "Date of Birth": "01-22-1963"
},
{
    "_id": ObjectId("4efa8d2b7d284dad101e4bc7"),
    "Last Name": "PELLERIN",
    "First Name": "Franck",
    "Date of Birth": "09-19-1983",
    "Address": "1 chemin des Loges",
    "City": "VERSAILLES"
}
Each document in a MongoDB collection can have different fields from the other documents (Note: "_id" field is obligatory, automatically created by MongoDB; it's a unique index which identifies the document. Its value need not be the default MongoID type shown here—the user may specify any non-array value for _id as long as the value is unique).

In a document, new fields can be added or existing ones suppressed, modified or renamed at any moment. There is no predefined schema. A document structure is very simple: it follows theJSON format, and consists of a series of key-value pairs, so that a document is the equivalent of the feature called in various computer languages "associative arrays", "maps", "dictionaries", "hash-tables" or "hashes". The key of the key-value pair is the name of the field, the value in the key-value pair is the field's content. The key and value are separated by ":", as shown.

A value can be a number; a string; true or false; binary data such as an image; an array of values (each of which can be of different type); or an entire subordinate document:

{
    "_id": ObjectId("4efa8d2b7d284dad101e4bc7"),
    "Last Name": "PELLERIN",
    "First Name": "Franck",
    "Date of Birth": "09-19-1983",
    "phoneNumber": [
        {
            "type": "home",
            "number": "212 555-1234"
        },
        {
            "type": "fax",
            "number": "646 555-4567",
            "verified":  false
        }
    ],
    "Address": {
        "Street": "1 chemin des Loges",
        "City": "VERSAILLES"
    },
    "Months at Present Address":  37
}

Here we can see that the field "Address" contains a subordinate document possessing two fields, "Street" and "City".

[edit]Language support

MongoDB has official drivers for a variety of popular programming languages and development environments.[15]. Web programming language Opa also has built-in support for MongoDB, which is tightly integrated in the language and offers a type-safety layer on top of MongoDB.[16] There are also a large number of unofficial or community-supported drivers for other programming languages and frameworks.[17]

[edit]HTTP/REST interfaces

There are REST and HTTP interfaces that allow the manipulation of MongoDB entries via HTTP GET, POST, UPDATE, and DELETE calls.

An overview of the available HTTP/REST interfaces can be found on the website of MongoDB

[edit]Management and graphical front-ends

[edit]MongoDB tools

In a MongoDB installation the following commands are available:

mongo
MongoDB offers an interactive shell called mongo,[18] which lets developers view, insert, remove, and update data in their databases, as well as get replication information, set up sharding, shut down servers, execute JavaScript, and more.
Administrative information can also be accessed through a web interface,[19] a simple webpage that serves information about the current server status. By default, this interface is 1000 ports above the database port (28017).
mongostat
mongostat[20] is a command-line tool that displays a summary list of status statistics for a currently running MongoDB instance: how many inserts, updates, removes, queries, and commands were performed, as well as what percentage of the time the database was locked and how much memory it is using. This tool is similar to the UNIX/Linux vmstat utility.
mongotop
mongotop[21] is a command-line tool providing a method to track the amount of time a MongoDB instance spends reading and writing data. mongotop provides statistics on the per-collection level. By default, mongotop returns values every second. This tool is similar to the UNIX/Linux top utility.
mongosniff
mongosniff[22] is a command-line tool providing a low-level tracing/sniffing view into database activity by monitoring (or "sniffing") network traffic going to and from MongoDB.mongosniff requires the Libpcap network library and is only available for Unix-like systems. A cross-platform alternative is the open source Wireshark packet analyzer which has full support for the MongoDB wire protocol.
mongoimport, mongoexport
mongoimport[23] is a command-line utility to import content from a JSON, CSV, or TSV export created by mongoexport[24] or potentially other third-party data exports. Usage information can be found in the MongoDB Manual's section on Importing and Exporting MongoDB Data.
mongodump, mongorestore
mongodump[25] is a command-line utility for creating a binary export of the contents of a Mongo database; mongorestore[26] can be used to reload a database dump. Data backup strategies and considerations are detailed in the MongoDB Manual's section on Backup and Restoration Strategies.

[edit]Monitoring plugins

There are MongoDB monitoring plugins available for the following network tools:

More monitoring and diagnostic tools for MongoDB are listed on MongoDB Admin Zone: Monitoring and Diagnostics

[edit]Cloud-based monitoring services

[edit]Web and desktop application GUIs

Several GUIs have been created by MongoDB's developer community to help visualize their data. Some popular ones are:

Open source tools

  • RockMongo: PHP-based MongoDB administration GUI tool
  • phpMoAdmin: another PHP GUI that runs entirely from a single 95kb self-configuring file
  • UMongo: a desktop application for all platforms.
  • Mongo3: a Ruby-based interface.
  • MeclipseEclipse plugin for interacting with MongoDB
  • MongoHub: a freeware native Mac OS X application for managing MongoDB. Version for other operating systems is built on Titanium Desktop.

More client tools for MongoDB are listed on MongoDB Administrator Manual

[edit]Business intelligence tools and solutions

  • Jaspersoft BI: Java based Report Designer and Report Server that supports MongoDB
  • RJMetrics: A hosted Business Intelligence Solution that supports MongoDB.
  • eCommerce Analytics: eCommerce Analytics Software that supports MongoDB data analysis.

[edit]See also

[edit]References

[edit]Bibliography

[edit]External links


출처 - http://en.wikipedia.org/wiki/MongoDB







'DB > MongoDB' 카테고리의 다른 글

mongodb - mongod.conf(web interface enable)  (0) 2013.05.19
mongo - 보안 및 계정 관리  (0) 2013.04.30
mongodb - Hadoop과 연동한 구축사례  (0) 2013.04.29
mongodb - 고려 사항  (0) 2013.04.29
MongoDB 소개  (0) 2013.01.07
Posted by linuxism
,


4.Java based Configuration

Spring 3에서는 Spring Java Configuration 프로젝트의 일부 주요 특징들을 추가함으로써 Java 기반의 Configuration 정의가 가능하도록 지원하고 있다. Java 기반의 속성 정의는 Java 코드를 중심으로 이루어지므로 Injection 속성 정의시 Type 오류가 있으면 컴파일부터 수행되지 않으므로 Type Safety를 보장하게 된다. 또한 Bean 인스턴스 관리를 로직으로 직접 구현해주기 때문에 Bean 구현체가 Spring에 의존되지 않고, 순수한 Java 코드로만 구현될 수 있도록 보장해준다.

활용 가능한 Annotation들은 위에서 나열한 바와 같으며, 본 섹션에서는 이러한 Annotation들에 대해 예제와 함께 자세히 살펴보도록 하자.

Java 기반의 Configuration 정의시 가장 기본이 되는 Annotation은 @Configuration과 @Bean이다. @Configuration은 클래스 레벨에 정의가능한 Annotation이다. @Configuration 정의를 포함한 클래스는 Bean 정의 정보를 담고 있어 Spring Container에 의해 처리되는 Configuration 클래스임을 의미한다. @Bean은 메소드 레벨에 정의 가능한 Annotation으로 XML 기반의 속성 정보 중 <bean/>과 동일한 역햘을 수행한다.

@Configuration
public class MovieFinderConfig {
    // ...
    @Bean
    public MovieFinder movieFinder() {
        return new MovieFinderImpl(movieDao);
    }
}

위 코드에서 언급한 MovieFinderConfig 클래스는 Configuration 클래스로써 'movieFinder'라는 이름을 가진 Bean을 정의하고 있음을 알 수 있다. 위 코드 내용을 XML 형태로 변경해 보면 다음과 같다.

<bean id="movieFinder" class="org.anyframe.sample.javaconfig.moviefinder.service.impl">
	<constructor-arg ref="movieDao"/>
</bean>

4.1.Bean Management

앞서 언급한 바와 같이 @Bean은 메소드 레벨에 정의 가능한 Annotation으로 특정 Bean을 정의하기 위해 사용한다. XML 기반의 속성 정보 중 <bean/>과 동일한 역햘을 수행하며, @Configuration 또는 @Component 클래스 내에 정의 가능하다. @Bean 정의가 추가된 메소드는 해당하는 Bean의 인스턴스 생성하여 전달하는 로직을 포함하고 있어야 하며 기본적으로 Spring Container는 메소드명을 Bean 이름으로 등록한다.

@Bean
public MovieFinder movieFinder() {
    return new MovieFinderImpl(movieDao);
}

위 코드에 의하면 @Bean 정의가 추가된 movieFinder() 메소드로 인해 'movieFinder'라는 이름의 Bean이 Spring Container에 등록될 것이다. 또한 'movieFinder' Bean을 요청하면 정의된 메소드 로직에 의해 MovieDao 객체가 셋팅된 MovieFinderImpl 객체가 전달될 것이다.

4.1.1.Naming

@Bean Annotation은 'name'이라는 속성 정보를 가지고 있다. name 속성에 대해 값을 부여하는 경우 이 값이 해당 Bean의 이름이 된다.

@Bean(name="movieFinderImpl")
public MovieFinder movieFinder() {
    return new MovieFinderImpl(movieDao);
}

4.1.2.Lifecycle Management

@Bean을 이용하여 정의된 Bean들에 대해서도 XML이나 Annotation 기반의 Bean들과 동일하게 기본 Lifecycle 관리가 가능하다. 즉, 해당 Bean이 @PreDestroy, @PostConstruct와 같은 JSR-250 Annotation을 포함하고 있거나 Spring의 InitializingBean, DisposableBean 등과 같은 인터페이스르 구현하였을 경우 Spring Container에 의해 해당 Bean의 Lifecycle이 관리된다. 이 외에도 @Bean은 'init-method', 'destroy-method'라는 속성 정보를 가질 수 있어서 속성값을 부여하는 경우 초기화/소멸화시에 정의된 메소드가 실행된다. 이것은 <bean/>의 init-method, destroy-method와 동일한 역할을 수행한다.

@Bean(initMethod = "initialize", destroyMethod = "destroy")
public MovieFinder movieFinder() {
    return new MovieFinderImpl(movieDao);
}

위 코드에 의하면 'movieFinder'라는 Bean의 초기화 시점에는 MovieFinderImpl.initialize(), 소멸화 시점에는 MovieFinderImpl.destroy() 메소드가 각각 실행될 것이다.

Spring Container는 시작 시점에 모든 Singleton Bean을 미리 로딩함으로써, 그 Bean이 필요할 때 즉시 사용될 수 있도록 보장해준다. 그러나 Container 시작 시점에 특정 Singleton Bean을 인스턴스화 시키지 않고 처음으로 해당 Bean에 대해 요청이 들어왔을 때 인스턴스화 시키기 위해서는 @Lazy 설정을 부여해 주어야 한다. 이것은 <bean/>의 lazy-init과 동일한 역할을 수행한다.

@Bean
@Lazy
public MovieFinder movieFinder() {
    return new MovieFinderImpl(movieDao);
}

4.1.3.Scope

@Bean과 함께 @Scope 정의를 추가하는 경우 해당 Bean에 대해 특정 Scope을 부여할 수 있다. @Scope을 부여하지 않는 경우 기본적으로 Singleton Scope이 적용된다.

@Bean
@Scope("prototype")
public MovieFinder movieFinder() {
    return new MovieFinderImpl(movieDao);
}

또한 request, session, globalSession Scope의 Bean에 대한 요청시 전달될 AOP Proxy 객체를 만들기 위해서 'proxyMode'라는 속성값을 추가적으로 부여할 수 있다. 'proxyMode'는 기본적으로 ScopedProxyMode.NO로 지정되며 ScopedProxyMode.TARGET_CLASS 또는 ScopedProxyMode.INTERFACES으로 정의 가능하다. 이것은 <bean/> 하위의 <aop:scoped-proxy/>와 동일한 역할을 수행한다.

@Bean
@Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
public MoviePreferences moviePreferences() {
    return new MoviePreferences();
}

@Bean
public MovieFinder movieFinder() {
    return new MovieFinderImpl(moviePreferences);
}

4.1.4.Dependency Injection

Bean 사이에 참조 관계가 성립될 경우 기본적으로 Injection은 참조하려는 Bean에 해당하는 메소드를 호출함으로써 이루어진다.

@Configuration
public class MovieFinderConfig {
    @Bean
    public MovieFinder movieFinder() {
        return new MovieFinderImpl(movieDao());
    }
    
    @Bean
    public MovieDao movieDao() {
        return new MovieDao();
    }    
}

'movieFinder' Bean이 'movieDao' Bean을 참조하고 있다라고 가정해 보자. 이를 Java 기반의 Configuration으로 표현하기 위해서는 위의 코드에서와 같이 movieFinder() 메소드 내에서 MovieFinderImpl 인스턴스 생성시 movieDao()라는 메소드를 호출함으로써 'movieDao' Bean을 Injection 할 수 있다. 또는 MovieFinderImpl 객체의 setter를 호출할 때 movieDao() 호출 결과를 전달함으로써 'movieDao' Bean을 Injection할 수도 있을 것이다.

@Configuration
public class MovieFinderConfig {
    @Bean
    public MovieFinder movieFinder() {
        MovieFinderImpl movieFinder = new MovieFinderImpl();
        movieFinder.setMovieDao(movieDao());
        return movierFinder;
    }
    
    @Bean
    public MovieDao movieDao() {
        return new MovieDao();
    }    
}

참조 대상 Bean이 XML/Annotation 기반으로 정의되었거나 다른 Configuration 클래스에 정의된 경우 Spring에서 Dependency Injection 처리를 위해 지원하는 Annotation(@Inject, @Autowired, @Resource)을 그대로 적용할 수도 있다.

@Configuration
public class MovieDaoConfig {

    @Bean
    public MovieDao movieDao() {
        MovieDao movieDao = new MovieDao();
        return movieDao;
    }
}
@Configuration
@Import(value = { MovieDaoConfig.class })
public class MovieFinderConfig {
    @Autowired
    private MovieDao movieDao;

    @Bean
    public MovieFinder movieFinder() {
        return new MovieFinderImpl(movieDao);
    }
}

해당 Bean 이전에 초기화되어야 하는 하나 이상의 Bean을 명시적으로 강제하기 위해서는 @DependsOn을 활용할 수 있다. 이것은 <bean/>의 depends-on와 동일한 역할을 수행한다.

@Configuration
public class MovieFinderConfig {
    @Bean
    public MovieService movieService(){
        return new MovieServiceImpl();
    }

    @Bean
    @DependsOn(value = { "movieService" })		
    public MovieFinder movieFinder() {
        return new MovieFinderImpl(movieDao());
    }

    // ...
}

위 코드에 의하면 @DependsOn 속성 부여에 의해 'movieFinder' Bean이 초기화되기 전에 'movieService' Bean이 초기화 될 것을 짐작할 수 있다.

동일한 Type을 가지는 Bean이 여러개 정의되어 있어서 Type Injection 대상이 되는 Bean이 여러개 식별되었을 경우 @Primary를 부여한 Bean이 우선적으로 Injection 후보가 된다. 이것은 <bean/>의 primary와 동일한 역할을 수행한다.

@Configuration
public class MovieDaoConfig {
    @Bean
    public MovieDao defaultMovieDao() {
        return new MovieDaoImpl();
    }

    @Bean
    @Primary
    public MovieDao anotherMovieDao() {
        return new AnotherMovieDaoImpl();
    }
}

위와 같이 Configuration을 정의한 경우 @Autowired MovieDao movieDao;와 같은 코드에 의해 Injection되는 Bean은 @Primary 속성을 부여한 'anotherMovieDao' Bean이 될 것이다.

4.1.5.Method Injection

Setter injection과 Constructor injection을 사용할 경우, 기본적으로 Singleton Bean은 참조하는 Bean들을 Singleton 형태로 유지하게 된다. 그런데 Singleton Bean이 Non Singleton Bean(즉, Prototype Bean)과 참조 관계가 있을 경우에는 다음과 같이 처리해야 한다.

  1. Singleton Bean의 구현체 내에는 참조하려는 Non Singleton Bean 타입을 리턴하는 abstract 메소드 정의.

  2. Singleton Bean의 구현체 내의 비즈니스 메소드에서는 abstract 메소드를 이용해 Non Singleton Bean을 Injection하여 로직 수행.

  3. Java 기반 Configuration 정의시 Singleton Bean에 해당하는 메소드 내에서 인스턴스 생성과 함께 앞서 정의한 abstract 메소드 구현 로직 추가. 이 때 abstract 메소드 구현 로직에서는 Non Singleton Bean의 인스턴스 생성하여 리턴.

  4. 위와 같은 순서로 처리된 경우 Singleton Bean의 비즈니스 메소드 내에서 abstract 메소드가 호출될 때마다 해당 Bean의 인스턴스가 가진 abstract 메소드 구현 로직에 의해 새로운 Non Singleton Bean의 인스턴스 전달이 가능해짐. 즉, Singleton Bean에서 Non Singleton Bean에 대한 참조가 가능해짐.

다음은 Singleton Bean('movieFinder')에서 Non Singleton Bean('movieDao')에 대한 참조가 이루어질 수 있도록 하기 위해 정의된 Configuration 클래스의 내용이다.

@Configuration
public class MovieFinderConfig {
    @Bean
    @Scope("prototype")
    public MovieDao movieDao() {
        return new MovieDaoImpl();
    }

    @Bean
    public MovieFinder movieFinder() {
        return new MovieFinderImpl() {
            protected MovieDao getMovieDao() {
                return movieDao();
            }
        };
    }
}

위 Configuration 클래스에서 언급한 MovieFinderImpl 클래스는 다음과 같은 모습을 취할 것이다.

public abstract class MovieFinderImpl implements MovieFinder {
    protected abstract MovieDao getMovieDao();

    public List<Movie> getPagingList(Movie movie, int pageIndex) 
        throws Exception{
        return getMovieDao().getPagingList(movie, pageIndex);
    }
}

4.1.6.Spring Expression Language

Java 기반 Configuration 정의시 @Value와 함꼐 Spring Expression Language를 정의하면 Expression 처리 결과를 Bean의 인스턴스 생성시 반영하는 것도 가능하다.

@Configuration
public class MovieFinderConfig {
    private @Value("${jdbc.url}") String dbUrl;
    private @Value("${jdbc.username}") String userName;
    private @Value("${jdbc.password}") String password;

    @Bean
    public MovieDao movieDao() {
        return new MovieDaoImpl(dbUrl, userName, password);
    }
}

4.1.7.Code Equivalents for Spring's XML namespaces

코드 기반으로 Spring의 XML 네임스페이스(<context:component-scan/>, <tx:annotation-driven/> and <mvc:annotation-driven>)에 대응하는 @Enable Annotation이 Spring 3.1 버전부터 추가되었다. 이러한 Annotation은 Spring 3.0부터 도입된 @Configuration 태그와 같이 사용하도록 설계되어 있다.

4.1.7.1.@ComponentScan

@Configuration 태그와 함께 사용하며 <context:component-scan>과 동일한 기능을 수행할 수 있다.

@Configuration
@ComponentScan("com.acme.app.services")
public class AppConfig {
    // various @Bean definitions ...
}

4.1.7.2.@EnableTransactionManagement

Spring에서 제공하는 Annotation 기반의 트랜잭션 관리 기능을 활성화시킨다. @Configuration 태그와 함께 사용하며, <tx:*>과 동일한 기능을 수행할 수 있다.

@Configuration
@EnableTransactionManagement
public class AppConfig {
    @Bean
    public FooRepository fooRepository() {
        // configure and return a class having @Transactional methods
        return new JdbcFooRepository(dataSource());
    }

    @Bean
    public DataSource dataSource() {
        // configure and return the necessary JDBC DataSource
    }

    @Bean
    public PlatformTransactionManager txManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

4.1.7.3.@EnableWebMvc

@Configuration 태그와 함께 사용하여 WebMvcConfigurationSupport클래스에 정의된 Spring MVC의 설정을 다음과 같이 불러올 수 있다.

@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyWebConfiguration {

}

WebMvcConfigurer 인터페이스를 구현하거나, WebMvcConfigurerAdapter 기반의 클래스를 확장하고 메소드를 오버라이딩 하여 불러들여진 설정을 다음과 같이 사용자화 할 수 있다.

@Configuration
@EnableWebMvc
@ComponentScan(basePackageClasses = { MyConfiguration.class })
public class MyConfiguration extends WebMvcConfigurerAdapter {

       @Override
       public void addFormatters(FormatterRegistry formatterRegistry) {
               formatterRegistry.addConverter(new MyConverter());
       }

       @Override
       public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
               converters.add(new MyHttpMessageConverter());
       }

       // More overridden methods ...
}

4.2.Combining Java and XML Configuration

@Import/@ImportResource를 활용하면 XML 또는 다른 @Configuration 클래스에 정의된 Bean 정보를 참조할 수 있게 된다.

4.2.1.Combine Java Configuration

@Import 정의시 다른 @Configuration 클래스를 속성값으로 부여해주면 현재 @Configuration 클래스에서 다른 @Configuration 클래스 내에 정의된 @Bean 정보를 참조할 수 있게 된다. Import 대상이 되는 @Configuration 클래스가 다수일 경우 { } 내에 ','를 식별자로 하여 클래스를 명시해주면 된다. @Import는 <import/>와 동일한 역할을 수행한다.

@Configuration
@Import(value = { MovieDaoConfig.class })
public class MovieFinderConfig {
    @Autowired
    private MovieDao movieDao;

    @Bean
    public MovieFinder movieFinder() {
        return new MovieFinderImpl(movieDao);
    }
}

@Configuration
public class MovieDaoConfig {
    // ...

    @Bean
    public MovieDao movieDao() {
        MovieDao movieDao = new MovieDao();
        return movieDao;
    }
}

위에서 언급한 @Configuration MovieFinderConfig 클래스는 MovieDaoConfig 클래스를 @Import하고 있어서 이 클래스 내에 정의된 Bean 'movieDao'를 참조할 수 있게 된다. 다른 @Configuration 클래스 내에 정의된 @Bean을 참조하기 위해서는 @Autowired를 사용하고 있음을 알 수 있다. @Inject, @Resource를 사용하는 것 또한 가능하다.

4.2.2.Combine XML Configuration

@ImportResource 정의시 XML 속성 파일의 위치를 속성값으로 부여해주면 현재 @Configuration 클래스에서 XML 내에 정의된 Bean 정보를 참조할 수 있게 된다. Import 대상이 되는 XML 파일이 다수일 경우 @Import와 동일한 형태로 { } 내에 ','를 식별자로 하여 XML 파일명을 명시해주면 된다.

@Configuration
public class MovieDaoConfig {

    @Bean
    public MovieDao movieDao() {
        MovieDao movieDao = new MovieDao();
        return movieDao;
    }
}

위 코드에서는 다른 XML 내에 정의된 Bean을 참조하기 위해 @Autowired를 사용하고 있음을 알 수 있다. @Inject, @Resource를 사용하는 것 또한 가능하다.

4.3.Instantiating spring container

Spring 3에서는 @Configuration 클래스를 인식하여 정의된 Bean들을 관리할 수 있도록 하기 위해 ApplicationContext의 구현체인 AnnotationConfigApplicationContext를 추가적으로 제공하고 있다. AnnotationConfigApplicationContext는 @Configuration 클래스 외에도 Stereotype Annotation, JSR-330 Annotation에 대해 인식 가능하다. 다음에서는 @Configuration 클래스를 기반으로 Spring Container를 시작시키는 방법에 대해서 살펴보도록 하자.

4.3.1.AnnotationConfigApplicationContext

XML/Annotation 기반에서 Spring Container를 시작시키기 위해서는 XmlWebApplicationContext, FileSystemXmlApplicationContext, ClassPathXmlApplicationContext와 같은 구현체를 활용했었다.

String[] locations = new String[] { "classpath:spring/context-*.xml" };
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(locations, false);
context.refresh();

그러나 @Configuration 클래스를 인식할 수 있도록 하기 위해서는 AnnotationConfigApplicationContext 구현체를 이용하여 Spring Container를 시작시켜야 한다. 인식해야 할 @Configuration 클래스가 다수일 경우 해당되는 클래스들을 입력 인자의 값으로 정의해주면 된다.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MovieFinderConfig.class, ...);

또는 AnnotationConfigApplicationContext의 Default Constructor를 호출하여 인스턴스를 생성한 뒤 인식 대상이 되는 @Configuration 클래스들을 register할 수도 있다.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MovieFinderConfig.class, ...);
context.register(...);
context.refresh();

Spring Container가 Annotation 기반의 Bean을 검색할 수 있게 하기 위해 정의한 <context:component-scan/>과 유사하게 AnnotationConfigApplicationContext을 이용하여 특정 패키지 하위에 대한 scan도 가능하다. 이렇게 하는 경우 해당 패키지 하위에 속한 모든 @Configuration 클래스가 검색되어 Container에 의해 처리된다.

AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.scan("org.anyframe.sample");
context.refresh();

4.3.2.AnnotationConfigWebApplicationContext

웹어플리케이션에서 @Configuration 클래스를 인식하여 Spring Container를 시작시키기 위해서는 ContextLoaderListener Listener의 속성 정보인 contextClass, contextConfigLocation의 값을 입력해주면 된다. 이 때, contextClass는 AnnotationConfigWebApplicationContext로 정의해주고, 이를 통해 로드될 @Configuration 클래스들을 contextConfigLocation의 속성값으로 부여해주도록 한다.

<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>org.anyframe.samples.moviefinder.basic.config.MovieFinderConfig</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Java 기반 Configuration 정의시 유의사항

다음 코드에서는 'movieFinder1', 'movieFinder2' Bean이 'movieDao' Bean을 참조하고 있다. 'movieDao' Bean을 참조하기 위해 movieDao() 메소드를 호출하고 있기 때문에 'movieFinder1', 'movieFinder2' Bean이 참조하는 MovieDao의 인스턴스가 다를 것이라고 기대할 것이다.

@Configuration
public class MovieFinderConfig {
			
    @Bean 
    public MovieFinder movieFinder1() {
        return new MovieFinderImpl(movieDao());
    }
    
    @Bean 
    public MovieFinder movieFinder2() {
        return new MovieFinderImpl(movieDao());
    }
		
    @Bean
    public MovieDao movieDao() {
        return new MovieDao();
    }
}

그러나 Spring에서는 초기화시에 CGLIB을 이용하여 모든 @Configuration 클래스에 대해 subclass화하고 subclass 내의 메소드에서는 특정 Bean의 인스턴스를 생성하기 전에 Container가 Caching된 Singleton Bean의 인스턴스가 있는지 체크하도록 처리하고 있기 때문에 'movieFinder1', 'movieFinder2'는 동일한 'movieDao' 인스턴스를 참조하게 된다.

설명한 바와 같이 Spring에서 @Configuration 클래스를 처리하기 위해 CGLIB을 사용하므로 해당 프로젝트에는 CGLIB 라이브러리가 반드시 필요하며, CGLIB을 이용하여 @Configuration 클래스에 대해 subclass화하는 작업을 위해 @Configuration 클래스는 Default Constructor를 반드시 가져야 하고 final로 정의되지 않도록 해야 함에 유의하도록 한다.

4.4.Resources

  • 다운로드

    다음에서 sample 코드를 포함하고 있는 Eclipse 프로젝트 파일을 다운받은 후, 압축을 해제한다.

    • Maven 기반 실행

      Command 창에서 압축 해제 폴더로 이동한 후, mvn compile exec:java -Dexec.mainClass=...이라는 명령어를 실행시켜 결과를 확인한다. 각 Eclipse 프로젝트 내에 포함된 Main 클래스의 JavaDoc을 참고하도록 한다.

    • Eclipse 기반 실행

      Eclipse에서 압축 해제 프로젝트를 import한 후, src/main/java 폴더 하위의 Main.java를 선택하고 마우스 오른쪽 버튼 클릭하여 컨텍스트 메뉴에서 Run As > Java Application을 클릭한다. 그리고 실행 결과를 확인한다.

    표 4.1. Download List

    NameDownload
    anyframe-sample-javaconfig.zipDownload


출처 - http://dev.anyframejava.org/docs/anyframe/plugin/essential/core/1.0.4/reference/html/ch04.html






CODE-BASED CONFIGURATION FOR SPRING MVC

Spring 3.1.0.M2 부터 기존에 사용하던 스프링 XML 설정 파일들을 거의 쓰지 않을 수 있게 되었습니다.

http://blog.springsource.com/2011/06/13/spring-3-1-m2-spring-mvc-enhancements-2/
http://blog.springsource.com/2011/06/10/spring-3-1-m2-configuration-enhancements/
https://github.com/SpringSource/greenhouse

persistence.xml 은 말로는 된다고 하나 코드를 열어 봤더니 아직 삭제할 수가 없고, web.xml을 전통적인 Servlet Spec 하에서 삭제하려면 Servlet 3.0 스펙이 필요해서 tomcat 7 을 써야합니다. 하지만, 현재 tomcat 7.0.16 + Spring 3.1.0.M2 조합하면 <form:form> 태그에서 NPE 가 발생합니다.

마일스톤 릴리즈는 Maven Central 에 없으므로 메이븐 저장소 설정을 해주어야 합니다.

<repositories>
    <repository>
        <id>org.springframework.maven.milestone</id>
        <name>Spring Maven Milestone Repository</name>
        <url>http://maven.springframework.org/milestone</url>
    </repository>
</repositories>

<properties>
    <org.springframework.version>3.1.0.M2</org.springframework.version>
    <org.springsecurity.version>3.1.0.M2</org.springsecurity.version>
</properties>

...

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>${org.springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>${org.springframework.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${org.springframework.version}</version>
</dependency>

web.xml 파일에서 Spring Context 로딩 방식이 달라집니다.

spring.xml 파일로 설정을 할 때는 web.xml 에 다음과 비슷하게 적으셨을 겁니다.

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/spring-config.xml</param-value>
</context-param>

Java Annotation 방식으로 하려면 아래와 같은 방식으로 수정합니다.

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextClass</param-name>
    <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</context-param>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>com.drypot.sleek.config</param-value>
</context-param>

여기서 contextConfigLocation 은 @Configuration 어노테이션이 붙은 클래스나 클래스가 들어 있는 패키지입니다.

XML 파일을 대신하는 @Configuration 클래스는 다음과 같이 기술됩니다.

@Configuration
@ComponentScan({"com.drypot.spring","com.drypot.sleek"})
@EnableTransactionManagement
@EnableWebMvc
public class SpringConfig extends WebMvcConfigurerAdapter {
...
}

@ComponentScan 은 기존의 <context:component-scan base-package=""/> 역할을 합니다.@EnableTransactionManagement 은 <tx:annotation-driven />@EnableWebMvc +WebMvcConfigurerAdapter 은 <mvc:annotation-driven /> 과 기타등등의 역할을 대신 합니다.

기존에 다음과 같이 <mvc:interceptors> 를 사용하셨다면 이것도 바꿀 수 있습니다.

<mvc:interceptors>
    <bean name="openSessionInViewInterceptor" class="org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor">
        <property name="entityManagerFactory" ref="emf" />
    </bean>
    <bean name="lastVisitUpdater" class="com.drypot.sleek.interceptor.LastVisitUpdater"/>
    <bean name="securityInterceptor" class="com.drypot.sleek.interceptor.SecurityInterceptor"/>
</mvc:interceptors>

를 아래와 같이.

@Bean
public OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor() {
    OpenEntityManagerInViewInterceptor openEntityManagerInViewInterceptor = new OpenEntityManagerInViewInterceptor();
    openEntityManagerInViewInterceptor.setEntityManagerFactory(emf());
    return openEntityManagerInViewInterceptor;
}

@Bean
public LastVisitUpdater lastVisitUpdater() {
    return new LastVisitUpdater();
}

@Bean 
public SecurityInterceptor securityInterceptor() {
    return new SecurityInterceptor();
}

@Override
public void configureInterceptors(InterceptorConfigurer configurer) {
    configurer.addInterceptor(openEntityManagerInViewInterceptor());
    configurer.addInterceptor(lastVisitUpdater());
    configurer.addInterceptor(securityInterceptor());
}

2011-08-29 01:15

Notes: 4 notes


출처 - http://drypot.tumblr.com/post/11188306289/code-based-configuration-for-spring-mvc#notes





@ComponentScan

@EnableAspectJAutoProxy

@EnableAsync

@EnableCaching

@EnableLoadTimeWeaving

@EnableSpringConfigured

@EnableTransactionManagement

@EnableWebMvc


참고  - http://cbeams.github.com/spring-3.1-review/#1





I am using jsf and spring together in web application. I have configured datasource and session factory in one configuration class which uses annotations like @Configuration, @ComponentScan etc. I don't have any applicationContext.xml file in my project as I am handling every entry of context xml in Configuration class. The test case works successfully but when I deploy my web application, it gives me error

java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?

Now if I give listener class in web.xml,

<listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

it gives me error,

/WEB-INF/applicationContext.xml not found

As per the document of ContextLoaderListener, it's true that if I don't givecontextConfigLocation param in web.xml explicitly, it will search for the default spring context file named applicationContext.xml in web.xml. Now, what should I do if I don't want to use spring context file and do all the configuration with annotations? How should I register listener classContextLoaderListener so that without use of xml file and using annotations only, I be able to run my web application with spring and jsf?

share|improve this question

10% accept rate
please take a look at How Accept Rate Works. Having a 0% accept rate will slow down responses to your questions in the future. – tolitius Nov 10 '11 at 18:12
Was this post useful to you?     

In web.xml you need to bootstrap the context with AnnotationConfigWebApplicationContext:

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            org.package.YouConfigurationAnnotatedClass
        </param-value>
    </init-param>
</servlet>

And don't forget to use @EnableWebMvc for your MVC annotations to kick in.

further reading:

EDIT as a "comments follow up" => to be Turing Complete:

Yes of course you need a listener. Although the above completely answers the question "How to register Spring @Configuration annotated class instead of applicationContext.xml file in web.xml", here is anexample from Spring official documentation that layouts the full web.xml:

<web-app>
  <!-- Configure ContextLoaderListener to use AnnotationConfigWebApplicationContext
       instead of the default XmlWebApplicationContext -->
  <context-param>
      <param-name>contextClass</param-name>
      <param-value>
          org.springframework.web.context.support.AnnotationConfigWebApplicationContext
      </param-value>
  </context-param>

  <!-- Configuration locations must consist of one or more comma- or space-delimited
       fully-qualified @Configuration classes. Fully-qualified packages may also be
       specified for component-scanning -->
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>com.acme.AppConfig</param-value>
  </context-param>

  <!-- Bootstrap the root application context as usual using ContextLoaderListener -->
  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- Declare a Spring MVC DispatcherServlet as usual -->
  <servlet>
      <servlet-name>dispatcher</servlet-name>
      <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
      <!-- Configure DispatcherServlet to use AnnotationConfigWebApplicationContext
           instead of the default XmlWebApplicationContext -->
      <init-param>
          <param-name>contextClass</param-name>
          <param-value>
              org.springframework.web.context.support.AnnotationConfigWebApplicationContext
          </param-value>
      </init-param>
      <!-- Again, config locations must consist of one or more comma- or space-delimited
           and fully-qualified @Configuration classes -->
      <init-param>
          <param-name>contextConfigLocation</param-name>
          <param-value>com.acme.web.MvcConfig</param-value>
      </init-param>
  </servlet>

  <!-- map all requests for /app/* to the dispatcher servlet -->
  <servlet-mapping>
      <servlet-name>dispatcher</servlet-name>
      <url-pattern>/app/*</url-pattern>
  </servlet-mapping>
</web-app>
share|improve this answer
Hi, I am not using Spring MVC here, only JSF and Spring 3.1 RC1. Though I wrote this servlet in my web.xml but still got same error "no ContextLoaderListener registered". I then did entry for listener class of spring and then got other error of applicationContext.xml not found. I hope I am making my point clear. – mitalpritmaniNov 10 '11 at 8:08
Hey, I got it worked when I added these 2 params as context params and spring listener class in web.xml. Thanks, your answer helped me to find out my answer. I am editing your answer to add my solution. You please approve it (as I don't have edit privileges) so that I can mark your answer as final. – mitalpritmani Nov 10 '11 at 9:36
I never received you edit request, but I updated my answer with an example of a full web.xml form the Spring official documentation. – tolitius Nov 10 '11 at 14:35
not an issue. The required answer is there now. Thanks. :) – mitalpritmani Nov 11 '11 at 5:52


출처 - http://stackoverflow.com/questions/8075790/how-to-register-spring-configuration-annotated-class-instead-of-applicationcont





SPRING 3.1 M2: SPRING MVC ENHANCEMENTS

Rossen Stoyanchev

This post focuses on what's new for Spring MVC in Spring 3.1 M2. Here are the topics:

  • Code-based equivalent for the MVC namespace.
  • Customizable @MVC processing.
  • Programming model improvements.

A brief reminder that the features discussed here are in action at theGreenhouse project.

CODE-BASED CONFIGURATION FOR SPRING MVC

As Chris pointed out in his blog post last Friday, XML namespaces cut down configuration dramatically but also reduce transparency and sometimes flexibility. This holds true for the MVC namespace, which supports a number of customizations but not everything that's available. That means you are either able to use it or otherwise leave it. We believe code-based configuration has a solution for that and a path from simple to advanced.

Let's begin with this simple, familiar snippet:

<mvc:annotation-driven />

Although not required for using annotated controllers, <mvc:annotation-driven> does a number of useful things — it detects the presence of a JSR-303 (Bean Validation) implementation and configures data binding with it, it adds a JSON message converter if Jackson JSON library is available, and a few other things that can save quite a bit of configuration.

Now let's match that with code-based configuration:

@Configuration
@EnableWebMvc
public class WebConfig {
}

Here @EnableWebMvc imports an @Configuration class that matches the goodness of<mvc:annotation-driven>. As simple as that.

The next step is to use an attribute in <mvc:annotation-driven> perhaps to provide aFormattingConversionService, or to add a sub-element perhaps configuring message converters, or to use other MVC namespace elements like<mvc:interceptors><mvc:resources>, etc.

Let's see how to do all of that in code-based configuration:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
 
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // register converters and formatters...
    }
 
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // add message converters...
    }
 
    @Override
    public void configureInterceptors(InterceptorConfigurer configurer) {
        configurer.addInterceptor(new AccountExposingHandlerInterceptor());
    }
 
    @Override
    public void configureResourceHandling(ResourceConfigurer configurer) {
        configurer.addPathMapping("/resources/**").addResourceLocation("/resources/");
    }
 
    // more @Override methods ...
 
}

Notice this time we've also sub-classed WebMvcConfigurerAdapter, a convenient base class with nothing but empty method implementations of the WebMvcConfigurer interface, which defines configuration callbacks for customizing the Spring MVC configuration.@Configuration classes that implement this interface are detected and given a chance to apply customizations. That's pretty much it.

The above provides parity with the MVC namespace in a way that is arguably moretransparent. You can use familiar Java IDE shortcuts to explore both theWebMvcConfigurer interface and the @Bean methods of the imported@Configuration class.

What about more advanced customizations? Well, this is as far as we can go with the MVC namespace. For code-based configuration, in the next (RC1) release, you'll be able to take the above example as is, drop the imported configuration (i.e. remove @EnableWebMvc) and switch to a base class that contains @Bean methods you can override. This means you can use Spring MVC code-based configuration knowing that any level of customization is possible — either through a simple callback mechanism or by extending directly from the class providing the actual configuration.

Here is a look at the web configuration in Greenhouse.

CUSTOMIZABLE @MVC PROCESSING

The @MVC programming model has been very successful enabling flexible controller method signatures. Yet many of you have asked for the underlying @MVC support classes to be more customizable. In response we've rolled a new set of @MVC support classes that give you more power and give us a better foundation to build on.

Before annotations, the Controller was the processing endpoint. With annotations the individual controller method became the endpoint complete with its own request mappings. Following this logic a HandlerMapping should not be limited to selecting a controller but should pick a controller method instead. Hence it will make sense that we've added aHandlerMethod abstraction and an AbstractHandlerMethodMapping for handler mappings that can select a HandlerMethod.

These are the new @MVC support classes built around the HandlerMethod abstraction:

  • RequestMappingHandlerMapping
  • RequestMappingHandlerAdapter
  • ExceptionHandlerExceptionResolver

As a result we now have a single point of selection in the handler mapping, the handler adapter knows exactly which handler method was selected, and so do other components. For example many of you requested to have interception around the invocation of a handler method, a gap that is now closed. Another less obvious consequence is the freedom to map the same URL across different controllers as long as the mapping differs in some other way (e.g. HTTP method).

Beyond request mapping, the execution of a controller method requires resolving method arguments (@RequestParameter@ModelAttribute, etc) and handling return values (@ResponseBody@ModelAttribute, etc.). The new @MVC support classes expose apluggable mechanism where implementations of HandlerMethodArgumentResolverand HandlerMethodReturnValueHandler can be plugged in to resolve every method argument and handle every return value. You have full control over that — you can either design your own argument types and return value types or customize the processing of the built-in ones. More details on that in a subsequent post.

To try the new @MVC support classes simply upgrade to Spring 3.1 M2. Both the MVC namespace and @EnableWebMvc configure them. Or if you have your own configuration just swap these:

  • DefaultAnnotationHandlerMapping -> RequestMappingHandlerMapping
  • AnnotationMethodHandlerAdapter -> RequestMappingHandlerAdapter
  • AnnotationMethodExceptionResolver ->ExceptionHandlerExceptionResolver

A note on compatibility: The existing support classes will continue to be available. However, we recommend that you switch going forward. For instance all the programming model improvements in the next section are only available that way. The new classes should be a drop-in replacement for the most part but there are two noteworthy differences. One, you can't combine any of the existing AbstractUrlHandlerMapping types (e.g.SimpleUrlHandlerMapping) with the new handler adapter, which expects aHandlerMethod and not a handler. Two, you can't rely on the method name when two@RequestMapping methods match equally to a request.

PROGRAMMING MODEL IMPROVEMENTS

This section lists programming model improvements introduced in the new @MVC support classes.

1. Declared @PathVariable arguments are now automatically added to the model. For example this:

@RequestMapping("/develop/apps/edit/{slug}")
public String editForm(@PathVariable String slug, Model model) {
    model.addAttribute("slug", slug);
    // ...
}

is replaced by:

@RequestMapping("/develop/apps/edit/{slug}")
public String editForm(@PathVariable String slug, Model model) {
    // model contains "slug" variable
}

2. Redirect strings support URI templates expanded with variables from the model (including declared @PathVariables). For example this:

@RequestMapping(
    value="/groups/{group}/events/{year}/{month}/{slug}/rooms",
    method=RequestMethod.POST)
public String createRoom(
    @PathVariable String group, @PathVariable Integer year,
    @PathVariable Integer month, @PathVariable String slug) {
    // ...
    return "redirect:/groups/" + group + "/events/" + year + "/" + month + "/" + slug;
}

is replaced by:

@RequestMapping(
    value="/groups/{group}/events/{year}/{month}/{slug}/rooms",
    method=RequestMethod.POST)
public String createRoom(
    @PathVariable String group, @PathVariable Integer year,
    @PathVariable Integer month, @PathVariable String slug) {
    // ...
    return "redirect:/groups/{group}/events/{year}/{month}/{slug}";
}

3. URI template variables are supported in data binding. For example this:

@RequestMapping("/people/{firstName}/{lastName}/SSN")
public String find(Person person,
                   @PathVariable String firstName,
                   @PathVariable String lastName) {
    person.setFirstName(firstName);
    person.setLastName(lastName);
    // ...
}

is replaced by:

@RequestMapping("/people/{firstName}/{lastName}/SSN")
public String search(Person person) {
    // person.getFirstName() and person.getLastName() are populated
    // ...
}

4. Consumable and producible media types can be specified via @RequestMapping. For example this:

@RequestMapping(value="/pets", headers="Content-Type=application/json")
public void addPet(@RequestBody Pet pet, Model model) {
    // ...
}

is replaced by:

@RequestMapping(value="/pets", consumes="application/json")
public void addPet(@RequestBody Pet pet, Model model) {
    // ...
}

Besides being shorter the above returns NOT_ACCEPTABLE (406) if the URL matches but the input media type doesn't.

5. For producible media types this:

@Controller
@RequestMapping(value = "/pets/{petId}", headers="Accept=application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {
    // ...
}

is replaced by:

@Controller
@RequestMapping(value = "/pets/{petId}", produces="application/json")
@ResponseBody
public Pet getPet(@PathVariable String petId, Model model) {
    // ...
}

The above returns a NOT_SUPPORTED_MEDIA_TYPE (415) if the URL matches but the acceptable media type doesn't.

SUMMARY

There is a lot that's new in this milestone release. I encourage everyone to try the changes and provide feedback ahead of the RC1 and GA releases.

I would also like to turn your attention to another on-going effort to provide integration test support to Spring MVC applications. For server-side test support see the spring-test-mvcproject available on Github. For client-side support check the Spring Social project or track the following JIRA ticket SPR-7951.

SIMILAR POSTS


출처 - http://blog.springsource.com/2011/06/13/spring-3-1-m2-spring-mvc-enhancements-2/





SPRING 3.1 M1: MVC NAMESPACE ENHANCEMENTS AND @CONFIGURATION

Rossen Stoyanchev

In this 5th post of the series describing Spring 3.1 M1 features, I will focus on web applications. In the first half I'll discuss enhancements to the MVC XML namespace. Then I'll show how to create the equivalent of the MVC namespace with all Java configuration. At the end I mention some of the Servlet 3.0 related configuration changes you can expect in 3.1 M2.

MVC NAMESPACE IMPROVEMENTS

Spring MVC 3.0 provided a custom MVC namespace. The centerpiece of the namespace — the <mvc:annotation-driven> element, configured everything required to process requests with annotated controller methods. More importantly though it set up a range of defaults that go along with having to do with type conversion, formatting, validation, reading and writing of the body of requests and respones and so on.

Over time a number of you have requested to gain more control over various aspects the above mentioned default configuration and we've addressed a number of those requests in the 3.1 M1 release.

Registration of Formatters

We'll start with the registration of Converters and Formatters, which is done by supplying your own ConversionService instance as follows:

<mvc:annotation-driven conversion-service="..." />

For custom Formatters you would subclassFormattingConversionServiceFactoryBean and register the Formatters in code. Starting with 3.1 M1 you can register Formatter andAnnontationFormatterFactory types declaratively using a setter:

<mvc:annotation-driven conversion-service="conversionService" />
 
<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="formatters">
        <list>
            <bean class="org.example.EmailFormatter"/>
            <bean class="org.example.PhoneAnnotationFormatterFactory"/>
        </list>
    </property>
</bean>

You still have the option to register Converters and Formatters in code. This is done with the FormatterRegistrar interface introduced in this release. Here is an example:

public class FinancialInstrumentFormatterRegistry implements FormatterRegistrar {
 
    public void registerFormatters(FormatterRegistry registry) {
        // Register custom Converters and Formatters here...
    }
 
}

And this is how your FormatterRegistrary can be plugged in:

<bean class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="formatterRegistrars">
        <list>
            <bean class="org.example.FinancialInstrumentFormatterRegistrar"/>
        </list>
    </property>
</bean>

So, when should you use a FormatterRegistrar as opposed to the formatters setter? AFormatterRegistrar is useful when you need to register multiple related converters and formatters for a specific formatting category from one place. Another case is registering aFormatter indexed under a field type other than its own generic type <T> or perhaps registering a Formatter from a Printer/Parser pair. A good example of an actualFormatterRegistrar implementation is the JodaTimeFormatterRegistrar in the Spring Framework so have a look in there.

One last option in the FormattingConversionServiceFactoryBean is the ability to turn off default Formatter registrations completely through theregisterDefaultFormatters flag.

Registration of HttpMessageConverters

Starting with 3.1 M1 you can register HttpMessageConverters through a sub-element ofmvc:annotation-driven. For example:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="com.google.protobuf.spring.http.ProtobufHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
            <property name="prefixJson" value="true"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

The list of message converters provided this way take priority over the message converters the MVC namespace registers by default. For example, above we've added one custom converter, ProtobufHttpMessageConverter and we've also provided an instance of the Spring MVC's MappingJacksonHttpMessageConvert customized according to application needs.

If you don't want any message converters to be registered by default use the register-defaults attribute on the <mvc:message-converters> element.

Registration of custom WebArgumentResolvers

WebArgumentResolver, if you've never seen one before, is used for resolving custom arguments in @RequestMapping methods. The Spring Mobile project has aSitePreferenceWebArgumentResolver. It resolves SitePreference method parameter types that indicate whether the user wants the mobile or the full version of a page. Starting with Spring 3.1 M1 you can register custom argument resolvers through the MVC namespace:

<mvc:annotation-driven>
    <mvc:argument-resolvers>
        <bean class="org.springframework.mobile.device.site.SitePreferenceWebArgumentResolver"/>
    </mvc:argument-resolvers>
</mvc:annotation-driven>

Custom MessageCodesResolver

Last in the list is the ability to provide a custom MessageCodesResolver:

<mvc:annotation-driven message-codes-resolver="messageCodesResolver" />
 
<bean id="messageCodesResolver" class="org.example.CustomMessageCodesResolver" />

There are lots of other things that could be done with the MVC namespace. The above list should help cover the most common use cases for added flexibility but do let us know if you think there are other important ones we've missed.

FROM XML TO @CONFIGURATION

Update
The information in this section is outdated. The approach was changed in milestone 2. Please read this Spring MVC 3.1 M2 post instead.

I this part of the post I'll take an existing sample application: the mvc-showcasethat many of you may be familiar with from prior posts by Keith Donald and replace its XML configuration with Java-based configuration. Doing that allow to compare the code and configuration before and after.

The resulting sample application is available for checkout at spring-3.1-mvc-java-config. You can browse the source code directly on GitHub or follow the README instructions and get the code locally.

Our first step is to modify web.xml to point to our Java-based configuration and to specify theApplicationContext type to use to process that configuration. Below is the relevant web.xml fragment:

<servlet>
    <servlet-name>appServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </init-param>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            org.springframework.samples.mvc.config.MvcFeatures
            org.springframework.samples.mvc.config.MvcBeans
        </param-value>
    </init-param>
</servlet>

Next we will create MvcFeatures and MvcBeans in the ~.config package. MvcFeaturescontributes @Feature methods and is our main point of interest:

@FeatureConfiguration
class MvcFeatures {
 
    @Feature
    public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
        return new MvcAnnotationDriven().conversionService(conversionService)
            .argumentResolvers(new CustomArgumentResolver());
    }
 
    // ...
 
}

The above snippet is the equivalent of this XML namespace configuration:

<mvc:annotation-driven conversion-service="conversionService">
    <mvc:argument-resolvers>
        <bean class="org.springframework.samples.mvc.data.custom.CustomArgumentResolver"/>
    </mvc:argument-resolvers>
</mvc:annotation-driven>

As you can see MvcAnnotationDriven provides the same options as the XML elements using a convenient chained method API. Also notice that we've declared aConversionService method parameter. This parameter is auto-wired by type and injected. Its declaration can be found in MvcBeans:

@Configuration
public class MvcBeans {
 
    @Bean
    public ConversionService conversionService() {
        DefaultFormattingConversionService bean = new DefaultFormattingConversionService();
        bean.addFormatterForFieldAnnotation(new MaskFormatAnnotationFormatterFactory());
        return bean;
    }
 
    // ...
 
}

Note the use of the DefaultFormattingConversionService rather than the familiarFormattingConversionServiceFactoryBean typically used in XML configuration. This former gives us the same default Converter and Formatter registrations as the latter but is better suited for use with Java configuration — it provides a simple constructor instead of the FactoryBean lifecycle initialization methods invoked by Spring when using XML.

The remaining portion of MvcFeatures declares the equivalent of the the<mvc:resources><mvc:view-controller>, and the <context:component-scan> elements:

@FeatureConfiguration
class MvcFeatures {
 
    // ...
 
    @Feature
    public MvcResources resources() {
        return new MvcResources("/resources/**", "/resources/");
    }
 
    @Feature
    public MvcViewControllers viewController() {
        return new MvcViewControllers("/", "home");
    }
 
    @Feature
    public ComponentScanSpec componentScan() {
        return new ComponentScanSpec("org.springframework.samples").excludeFilters(
                new AnnotationTypeFilter(Configuration.class),
                new AnnotationTypeFilter(FeatureConfiguration.class));
    }
}

There are two things worth noting. One is that a single instance of MvcViewControllersis needed to define any number of view controllers using chained method calls. The second is the use of an exclude filter in the componentScan() method in order to preventMvcFeatures and MvcBeans from getting registered twice — once by theAnnotationConfigWebApplicationContext and a second time by the component scan.

For completeness this is the remaining part of MvcBeans:

@Configuration
public class MvcBeans {
 
    // ...
 
    @Bean
    public InternalResourceViewResolver jspViewResolver() {
        InternalResourceViewResolver bean = new InternalResourceViewResolver();
        bean.setPrefix("/WEB-INF/views/");
        bean.setSuffix(".jsp");
        return bean;
    }
 
    @Bean
    public MultipartResolver multipartResolver() {
        return new CommonsMultipartResolver();
    }
}

The last step is to remove the Spring XML configuration located under /WEB-INF/spring.

SUMMARY

So there we are. We've bootstrapped a web application with all Java-based Spring configuration. Now that @FeatureConfiguration and @Feature have been introduced you can expect to see more and more FeatureSpecification implementations as an alternative to custom XML namespaces. I rather like the end result of the Java configuration but of course that doesn't mean my existing applications need to switch. It's all about having choice. If you prefer the declarative nature of XML and you use an IDE with code completion on class and method names in Spring XML configuration, then using XML namespaces is fine as well.

As heard recently in the webinar Introducing Spring Framework 3.1, in milestone 2 of Spring 3.1 you can expect to see Servlet 3.0 support including XML-free web application setup (i.e no web.xml) in combination with AnnotationConfigWebApplicationContext and the environment abstraction demonstrated in this and the previous posts of this blog series.

We hope you like these features and find them useful. Please let us know what you think.

SIMILAR POSTS

Share this Post
  • Digg
  •  
  • Sphinn
  •  
  • del.icio.us
  •  
  • Facebook
  •  
  • Mixx
  •  
  • Google Bookmarks
  •  
  • DZone
  •  
  • LinkedIn
  •  
  • Slashdot
  •  
  • Technorati
  •  
  • Twitter
 


출처 - http://blog.springsource.com/2011/02/21/spring-3-1-m1-mvc-namespace-enhancements-and-configuration/



Posted by linuxism
,