Maven Chapter5 Page 1 Table of Contents Table of Contents... 1 Revision History... 2 1. 내가꿈꾸는개발환경... 3 2. 메이븐설치및템플릿프로젝트생성... 3 3. 메이븐설정파일... 3 4. 메이븐라이프사이클 lifecycle... 3 5. 메이븐을이용한의존라이브러리관리... 3 5.1 메이븐의의존라이브러리관리 Dependency... 4 5.2 위키북프로젝트에의존라이브러리추가하기...16 5.3 속성 properties...25 6. 메이븐과이클립스통합... 28 7. 메이븐과데이터베이스통합... 28 8. 메이븐프로파일, 배포... 28 9. 리포팅기능을활용한문서관리... 28 10. 메이븐모듈 module... 28 11. 메이븐사내저장소설치및활용... 28 12. 표준 POM 파일생성및리팩토링... 28 13. 메이븐아키타입 archetype... 28 14. 새로운프로젝트를시작하면서..... 28
Maven Chapter5 Page 2 Revision History Name Date Reason For Changes Version
Maven Chapter5 Page 3 1. 내가꿈꾸는개발환경 2. 메이븐설치및템플릿프로젝트생성 3. 메이븐설정파일 4. 메이븐라이프사이클 lifecycle 5. 메이븐을이용한의존라이브러리관리 프로젝트시작 4 일째 ( 소제목 ) 메이븐의빌드과정에대하여이해했으니이제부터본격적으로위키북프로젝트를진행할수있겠다. 먼저위키북프로젝트와의존관계에있는라이브러리를추가해야겠다. 위키북프로젝트는전사표준프레임워크인스트럿츠 2 struts2, 스프링 spring, 아이바티스 ibatis 프레임워크를기반으로진행해야하기때문에먼저이세개의프레임워크라이브러리를추가해야겠다. 그이후에이세개의프레임워크라이브러리와의존관계에있는라이브러리를추가하면되겠지. 이젠정말위키북프로젝트를진행하는기분이든다. 그런데메이븐에서는라이브러리는어떻게추가할까? 지금까지는의존관계에있는라이브러리를일일이다운로드한후에복사해서사용했는데좀불편한것이사실이었다. 예를들어스프링프레임워크기반으로애플리케이션을개발할때스프링프레임워크의버전을변경하고자한다면다음과같은과정을통하여변경했다.
Maven Chapter5 Page 4 그림 5-1 새로운버전의스프링프레임워크라이브러리를변경할때의사이클 그림 5-1 을통하여확인할수있듯이하나의라이브러리버전을변경하려면여러단계를거쳐야했다. 애플리케이션을개발하는데사용하는외부라이브러리가점점더많아지고복잡해지는상황에서현재와 같은라이브러리관리방법은한계를가질수밖에없었다. 메이븐은좀더편한방법으로라이브러리를관리하면좋겠다. 오늘은위키북프로젝트에스트럿츠 2, 스프링, 아이바티스프레임워크에대한의존관계를설정하면서메이븐이의존관계에있는라이브러리를 관리하는방법에대하여학습해봐야겠다. 5.1 메이븐의의존라이브러리관리 Dependency 메이븐은의존관계에있는라이브러리를관리하기위하여의존라이브러리관리 Dependency 기능을제공한다. 이기능은라이프사이클과더불어메이븐의중심에있는기능중의하나로반드시이해해야하는기능이다. 메이븐을처음사용할때개발자가가장좋아하지만문제가발생할가능성이가장높은기능이바로이기능이다. 이기능을제대로이해하고메이븐을사용한다면메이븐을사용하면서발생하는문제들을쉽게해결할수있을것이다. 하지만제대로이해하지못하는경우어디서문제가발생하는지해결책을찾지못해몇일을소비할수도있다. 메이븐에서중요한기능인만큼이장의내용은반드시이해해야한다. 5.1.1 메이븐저장소
Maven Chapter5 Page 5 메이븐의의존라이브러리관리기능에대하여이해하려면먼저메이븐의저장소에대하여이해해야한다. 메이븐저장소는다음과같이세가지로나눌수있다. 1 중앙저장소 : 오픈소스라이브러리, 메이븐플러그인, 메이븐아키타입을관리하는저장소이다. 메이븐 2.0 의중앙저장소 URL 은 http://repo1.maven.org/maven2/ 이다. 중앙저장소는원격 저장소중의하나이다. 중앙저장소는임의의개발자가라이브러리를배포할수없다. 원격저장소 : 메이븐기반으로프로젝트를진행하는경우프로젝트에필요한모든라이브러리가메이븐중앙저장소에존재하는것이아니다. 이처럼중앙저장소에존재하지않는라이브러리를관리하기위하여별도의메이븐저장소를설치해관리하는것이가능하다. 원격저장소는회사내에서만사용하기위한용도의사내원격저장소와스프링소스 SpringSource 에서제공하고메이븐저장소와같이외부에위치하는외부 ( 공개 ) 원격저장소가있다. 로컬저장소 : 로컬저장소는메이븐을빌드할때다운로드하는라이브러리, 플러그인을관리하는 저장소이다. 기본로컬저장소는 USER_HOME/.m2/repository 디렉토리이다. 각각의저장소와메이븐페이즈와의관계를도식화해보면다음그림과같다. 그림 5-2 메이븐라이브러리와저장소의관계도 1 구분방법에따라원격저장소와로컬저장소로나눌수도있으며, 사내원격저장소, 공개원격저장소, 로컬저장소로나눌수도있다. 이책에서는메이븐중앙저장소를별도의용도로설명하는경우가많아 별도로분리하여설명했다.
Maven Chapter5 Page 6 메이븐은빌드를하는시점에중앙저장소나외부에위치하는원격저장소에서로컬저장소로오픈소스 라이브러리, 메이븐플러그인라이브러리를다운로드한다. 로컬저장소에이미다운로드한라이브러리가 존재하면다시다운로드하지않고로컬저장소의라이브러리를사용한다. package 페이즈를실행하여메이븐기반프로젝트를 <packaging/> 엘리먼트설정에따라 jar, war, ear 의형태로압축을한다. 이와같이압축한결과물은 install 페이즈를실행하여로컬저장소에배포가된다. 로컬저장소에배포한라이브러리는개발자 PC 의다른프로젝트에서만의존관계를설정할수있다. 로컬저장소에만배포할경우다른개발자와라이브러리를공유할수없다. 다른개발자와라이브러리를공유하기위해서는 deploy 페이즈를실행해배포권한이있는원격저장소에배포해야한다. 중앙저장소와외부원격저장소는특정프로젝트의라이브러리나사내에서만사용하는라이브러리를배포할수없다. 이작업이가능하도록지원하기위해서는별도의메이븐사내원격저장소를설치하고관리해야한다. 사내메이븐원격저장소를설치하고활용하는방법에대해서는 11 장에서다룬다. 5.1.2 메이븐저장소설정 메이븐에서저장소에대한설정은 <repositories>/<repository> 엘리먼트에서설정한다. 최상위 POM 에 설정되어있는중앙저장소의설정을보면다음과같다. <project...> <repositories> <repository> <id>central</id> <name>maven Repository </name> <url>http://repo1.maven.org/maven2</url> </repository> </repositories> </project> 대부분의오픈소스라이브러리는중앙저장소에서제공하고있다. 하지만일부라이브러리는별도의메이븐원격저장소를통하여제공하는경우가있다. 이와같이중앙저장소에서제공하지않는라이브러리가있다면 <repository/> 엘리먼트에 id, name, url 값을설정하면된다. id, name 값은임의의값을사용하면되고, url 은원격저장소의 url 을설정하면된다. 메이븐은라이브러리를다운로드할때 <repositories/> 엘리먼트에설정되어있는저장소순서로라이브러리를다운로드한다. 첫번째저장소에서의존관계에있는라이브러리를찾았다면다음저장소에접근하지않고다른라이브러리를찾는방식으로동작한다.
Maven Chapter5 Page 7 5.1.3 메이븐의존라이브러리관리 이절에서는배포 (install, deploy 페이즈 ) 와관련된부분은제외하고의존관계에있는라이브러리를 다운로드하기위하여 pom.xml 을설정하는방법과메이븐의의존라이브러리관리기능에대한동작 방식에대하여설명하도록하겠다. 예를들어앞에서생성한위키북프로젝트의 <dependencies/> 엘리먼트를이용하여메이븐중앙 저장소에서라이브러리를관리하는방법부터살펴보겠다. 위키북프로젝트의 <dependencies/> 엘리먼트는 다음과같다. <project...> [...] <dependencies> <groupid>junit</groupid> <artifactid>junit</artifactid> <version>3.8.1</version> <scope>test</scope> </dependencies> [...] </project> 예제 5-1 위키북프로젝트의 <dependencies/> 엘리먼트예제소스 예제 5-1 의 <dependencies/> 엘리먼트가복수를의미하듯이이엘리먼트하위에는여러개의 <dependency/> 엘리먼트를가질수있다. 예제 5-1 은위키북프로젝트가 junit 3.8.1 버전과의존관계에있다고설정한것이다. pom.xml 파일을위와같이설정한다음빌드를실행하면메이븐중앙저장소에서 junit 3.8.1 버전의 jar 파일을자동으로로컬저장소에다운받는다. 과정은다음과같다. 메이븐은중앙저장소에 junit 3.8.1 버전이있는지확인하고해당버전이있다면 junit 3.8.1 버전을다운받는다. 버전을찾는과정은메이븐중앙저장소 (http://repo1.maven.org/maven2/) 에접근하여 groupid/artifactid/version 에존재하는 ${artifactid}-${version}.jar 파일을다운로드한다. 따라서예제 5.1 의설정은최종적으로 http://repo1.maven.org/maven2/junit/junit/3.8/junit-3.8.jar 파일이존재하는지를파악해존재할경우다운로드한다. 메이븐로컬저장소의변경없이기본디렉토리를사용할경우 USER_HOME/.m2/repository (USER_HOME 디렉토리는윈도우 XP 는 C:\Documents and Settings\${userid}, 리눅스는 /home/\${userid} 이다.) 디렉토리에모든의존성라이브러리를다운로드한다. 로컬저장소에라이브러리를관리하는규칙또한중앙저장소와동일하다. 예제 5-1 과같이 pom.xml 파일을설정한다면 USER_HOME/.m2/repository/junit/junit/3.8.1/ 디렉토리에 junit-3.8.1.jar 파일이다운받아진다.
Maven Chapter5 Page 8 groupid 는일반적으로도메인명을사용한다고했다. 위키북프로젝트의경우 groupid 가 net.javajigi, artifactid 가 wikibook 이다. 이와같이도메인명을사용했을때라이브러리가위치하는디렉토리는 USER_HOME/.m2/repository/net/javajigi/wikibook/1.0-SNAPSHOT/ 이다. 이처럼 groupid 에도메인명을사용할경우점 (.) 을기준으로디렉토리를분리해관리한다. 예제 5-1 과같이 JUnit 라이브러리에대한의존관계를설정한상태에서 JUnit 버전이업그레이드되어 버전을변경하고자한다면 pom.xml 파일에서버전번호만변경하면된다. 예를들어 JUnit 라이브러리를 4.7 버전으로변경한다면다음과같이설정하면된다. <project...> [...] <dependencies> <groupid>junit</groupid> <artifactid>junit</artifactid> <version>4.7</version> <scope>test</scope> </dependencies> [...] </project> 예제 5-2 JUnit 버전을 3.8.1 에서 4.7 버전으로변경하는예제소스 예제 5-2 와같이 JUnit 의버전을 3.8.1 에서 4.7 로변경하면로컬저장소에 JUnit 4.7 버전이없으므로 빌드를하는과정에서 JUnit 4.7 버전을다운로드한다. 만약이미다운로드한 JUnit 4.7 버전이존재한다면 로컬저장소에있는 JUnit 4.7 버전을활용한다.
Maven Chapter5 Page 9 그림 5-3 메이븐을빌드할때 JUnit 4.7 버전을다운로드하는화면 그림 5-3 을보면 JUnit 4.7 버전이로컬저장소에존재하지않을경우중앙저장소의 jar 파일을로컬저장소에다운로드한다. 메이븐빌드를실행해로컬저장소에의존관계에있는라이브러리를한번다운로드하면두번째실행부터는다시다운로드하지않는다. 따라서의존관계를설정하고메이븐빌드를처음실행할때는관련된라이브러리를다운로드하느라많은시간이소요된다. 하지만두번째빌드부터는한번다운로드한라이브러리를다운로드하지않기때문에빌드속도가빨라진다. 앞에서다운로드한라이브러리를로컬저장소에서관리할때의디렉토리구조는다음과같다.
Maven Chapter5 Page 10 그림 5-4 메이븐로컬저장소의디렉토리구조 그림 5-4 에서보는바와같이같은 groupid 와 artifactid 아래에각버전에따른라이브러리를관리하는 방식으로라이브러리를관리한다. 메이븐은프로젝트를빌드할때로컬저장소에다운로드한라이브러리로 src/main/java 와 src/test/java 의소스코드를컴파일한다. 메이븐에서는의존관계에있는라이브러리를 pom.xml 파일을활용해관리하므로 CVS, SVN 과같은버전관리시스템 (Version Control System, VCS) 으로라이브러리를관리할필요없이 pom.xml 파일만공유하면된다. 지금까지버전관리시스템으로관리하는프로젝트파일크기의대부분이의존관계에있는라이브러리가차지했었다. 메이븐에서는 pom.xml 만관리하면되므로버전관리시스템으로공유할소스코드의크기가작다. < 참고사항 > 앤트를사용하던개발자들이메이븐을처음접했을때가장당황스러워하는부분이의존관계에있는라이브러리가프로젝트소스에포함되어있지않다는것이다. 앤트를사용할경우에는라이브러리를관리할수있는다른방법이없었기때문에프로젝트에포함시킬수밖에없었다. 하지만프로젝트소스와의존관계에있는라이브러리는분리해서관리하는것이바람직하다. 그이유는다음과같다. 프로젝트전체파일크기가커짐으로인해버전관리시스템을통하여소스코드를공유하는데 추가적인비용이발생한다. 라이브러리에대한히스토리관리와버전관리를제대로관리하지않을경우중복된라이브러리가 포함되어문제가발생할가능성이있다.
Maven Chapter5 Page 11 따라서메이븐에서지원하는것처럼의존관계라이브러리와프로젝트소스를별도로관리하고유지할수 있도록지원하는것이좋은선택이다. 최근에는앤트에서도앤트립, 아이비 ivy 2 를이용하여메이븐의의존 라이브러리관리기능을사용할수있다. 모든개발자가앤트에익숙한상태이고메이븐에대한경험을가지고있는개발자가없는상태라면먼저앤트립, 아이비를이용하여메이븐의의존라이브러리관리기능을경험해보는것도좋은전략이다. 메이븐의의존라이브러리관리기능에익숙해진상태에서메이븐으로전환한다면메이븐에대하여호감을가진상태이기때문에메이븐으로전환하는데거부감이줄어들것이다. </ 참고사항 > 메이븐은 pom.xml 파일에저장소를설정하지않을경우 http://repo1.maven.org/maven2/ 를기본저장소로설정한다. 기본저장소에대한설정은앞에서살펴본바와같이최상위 POM 에서관리하고있다. 따라서프로젝트에추가하고자하는라이브러리가있다면 http://repo1.maven.org/maven2/ 에서찾을수있다. 앞에서다운로드한 JUnit 라이브러리도 http://repo1.maven.org/maven2/ 에서찾을수있다. 메이븐중앙저장소에서관리하는라이브러리의버전을알고싶다면먼저메이븐중앙저장소로접근한 다음, groupid/artifactid 로접근하면해당라이브러리가지원하는버전을알수있다. JUnit 의버전을알고 싶다면 http://repo1.maven.org/maven2/junit/junit/ 에서지원하는버전정보를얻을수있다. 2 http://ant.apache.org/ivy/. 프로젝트의라이브러리관리기능을지원하기위하여등장한도구이다. 앤트와 통합하여사용하는것이가능하다.
Maven Chapter5 Page 12 그림 5-5 메이븐중앙저장소의 Junit 버전을확인하는화면 그림 5-5 와같이해당라이브러리에서사용가능한버전을확인한다음 pom.xml 설정파일의버전을변경하면된다. 그러나메이븐중앙저장소에서관리하는라이브러리의수는한두개가아니다. 한프로젝트에서사용하는라이브러리의수가많아서위와같은방법으로라이브러리를추가하는데는한계가있다. 이런단점을극복하기위하여 http://mvnrepository.com/ 사이트에서메이븐중앙저장소에서관리하는라이브러리를검색할수있다. 예를들어메이븐저장소에서관리하는 JUnit 테스트프레임워크에대한라이브러리정보를찾고자한다면 http://mvnrepository.com/ 에서 junit 으로검색한다. 그림 5-6 MvnRepository 에서 junit 으로검색한결과화면
Maven Chapter5 Page 13 위결과화면에서추가하고자하는 JUnit 테스트프레임워크모듈을선택한다. 그림 5-6 에서 junit >> junit 을선택한다음사용할버전을선택하면다음과같이 pom.xml 에추가할수있는 <dependency/> 엘리먼트정보를찾을수있다. 그림 5-7 mvnrepository.com 에서 JUnit 라이브러리 4.7 버전을선택한결과화면 그림 5-7 에서 POM Dependency 의 <dependency/> 엘리먼트를 pom.xml 파일에복사하면 JUnit 라이브러리를사용하기위한모든준비가완료되었다. 메이븐으로빌드하면 JUnit 4.7 버전이로컬저장소에다운로드된다. 메이븐중앙저장소를직접이용해도되지만, 라이브러리를검색하는기능을제공하고있지않기때문에 http://mvnrepository.com/ 를활용하는것이더바람직한선택이다. 이사이트에서도찾기힘들다면검색사이트를활용해각라이브러리에대한의존관계설정정보를찾을수있다. 5.1.4 의존라이브러리버전 메이븐은의존관계에있는라이브러리의버전을효율적으로관리할수있도록몇가지옵션을제공하고 있다.
Maven Chapter5 Page 14 가장일반적인방법은 1.0 과같이명시적으로버전정보를지정하는것이다. 하지만명시적으로버전 정보를지정하지않고범위를두어버전을관리할수있다. 버전의범위를지정할때사용할수있는형식은 다음과같이두가지를옵션을사용할수있다. (,) : 해당버전을제외 [,] : 해당버전을포함 예를들어 JUnit 라이브러리의버전을 3.8 보다크거나같고, 4.8 보다작은범위의라이브러리와의존 관계를가지도록설정하고싶다면다음과같이설정할수있다. <groupid>junit</groupid> <artifactid>junit</artifactid> <version>[3.8,4.8)</version> 위와같이설정하면저장소에존재하는 JUnit 라이브러리버전중에서 4.8 보다작으면서 3.8 보다크거나같은버전중에서가장최신버전과의존관계를가진다. JUnit 라이브러리는 4.8 보다작은버전중최신버전이 4.7 버전이기때문에 4.7 버전과의존관계를가지도록설정된다. 의존관계라이브러리를관리할때라이브러리의버전이변경될때마다매번버전을변경하는것이불편할수있다. 이와같이매번버전번호를변경하지않고가장최신버전의라이브러리와의존관계를가지도록설정할수있다. <version>latest</version> 또는 <version>release</version> 이와같이 LATEST 와 RELEASE 를사용함으로써가장최신버전과의존관계를가지는방법이있지만이 방법을사용할경우라이브러리의버전이자동으로변경됨으로써이전에정상적으로동작했던기능이 비정상적으로동작할가능성이있기때문에좋은선택은아니다. 메이븐은처음빌드할때중앙저장소에서라이브러리를다운로드한다. 한번다운로드를완료한후버전이같으면다시다운로드하지않는다. 라이브러리가최종적으로배포한상태에서는이방법이유효하다. 그러나애플리케이션을개발하는과정에서소스코드는지속적으로변경되기때문에지속적으로배포하고사용할수있어야한다. 이와같이개발중인라이브러리나프로젝트에대해서는 SNAPSHOT 을사용할수있다. 버전정보에 SNAPSHOT 을포함하면빌드할때마다가장최근에배포한라이브러리가있는지를파악해로컬저장소에존재하는버전보다최신버전의라이브러리가존재할경우다운로드한다. 따라서변경되는소스코드에대하여지속적으로배포하고참조하는것이가능하다. 프로젝트를진행하는중에는
Maven Chapter5 Page 15 1.0-SNAPSHOT 과같이 SNAPSHOT 버전으로유지하고프로젝트를완료하고배포하는시점에최종 버전으로관리하는것이효율적인관리방식이다. 5.1.5 의존라이브러리의적용스코프 scope 메이븐은사용하는라이브러리의성격에따라스코프를지정할수있다. 예를들어 JUnit 은테스트에만사용하고실제배포할때는필요없는라이브러리다. 각라이브러리에대한스코프는 <dependency/> 엘리먼트아래에 <scope/> 엘리먼트를활용해설정할수있다. JUnit 라이브러리를테스트스코프에서만의존관계를가지도록설정하면다음과같다. <groupid>junit</groupid> <artifactid>junit</artifactid> <version>4.7</version> <scope>test</scope> 이와같이라이브러리가필요한스코프에따라 6 가지로지정한다. compile: 스코프를설정할지않았을때의기본스코프이다. 컴파일시에도사용되며, 배포시에도같이배포되어야하는라이브러리이다. provided: 예를들어 servlet.jar 는서블릿컨테이너에서제공하므로컴파일시점에는필요하지만, 애플리케이션을배포할때같이배포될필요는없다. 이와같은상황에서사용하는스코프이다. runtime: runtime 스코프는말그대로컴파일시에는사용되지않지만애플리케이션을실행할때사용되는라이브러리일경우설정한다. test: 테스트하는시점에만사용하는라이브러리에대한스코프를설정할때사용한다. system: system 스코프는 provided 와비슷하다. 단지우리가직접 jar 파일을제공해야한다. 따라서이스코프의 jar 파일은저장소에서관리되지않을수도있다. import( 메이븐 2.0.9 이후버전부터사용가능 ): 다른 POM 설정파일에정의되어있는의존관계설정을현재프로젝트로가져온다. 이범위는 <dependencymanagement/> 엘리먼트에서만사용가능하다. 이와같이메이븐을적용스코프를두어빌드하는시점에필요한라이브러리만압축이되도록설정하는것이가능하다.
Maven Chapter5 Page 16 5.2 위키북프로젝트에의존라이브러리추가하기 5.2.1 스트럿츠 2, 스프링, 아이바티스라이브러리의존성추가 메이븐이의존라이브러리를관리하는방법과라이브러리를찾는방법도알았으니위키북프로젝트와의존관계에있는라이브러리에대한설정을추가하는작업을해야겠다. 먼저위키북프로젝트의핵심프레임워크인스트럿츠 2, 스프링, 아이바티스에대한의존관계설정부터추가해보자. 먼저오늘학습한데로 http://mvnrepository.com/ 사이트에접속해검색을통해서라이브러리를추가해야겠다. struts2, spring, ibatis 로검색을했더니너무많은라이브러리가검색이되어어떤라이브러리를활용해야될지모르겠다. 역시공부할때참고했던문서와실전에서적용할때부딪히는문제는다르다. 는생각을다시한번느낀다. 설마이런부분까지활용하기힘들줄몰랐는데잠시배신감을느낀다. 그래도검색결과를보니내가원하는라이브러리가있는데검색조건을줄일수있는방법이없을까? 곰곰히생각하던중 대부분의라이브러리는 groupid 로도메인이름을사용하고있으니도메인이름으로검색해보자. 는결론을내리고구글에서각프레임워크에대한도메인을찾았다. 다시한번스트럿츠 2 는 org.apache.struts, 스프링은 org.springframework, 아이바티스는 org.apache.ibatis 로각각검색을했더니내가원하는검색결과가나타났다. 특히아이바티스검색결과는 내가원하는검색결과만을볼수있었다. 그림 5-8 org.apache.ibatis 검색결과화면 단, 스트럿츠 2 의경우에는스트럿츠 1 결과와같이뒤섞이기기는했지만나에게필요한라이브러리를 추가하는데특별히문제가되지는않았다. 역시모든책과문서가완벽한해결책을제시해주기는힘들고
Maven Chapter5 Page 17 문제가발생하는순간다른해결책을찾는능력이정말중요하다는것을느꼈다. 이과정을통해스트럿츠 2, 스프링, 아이바티스에대한의존관계설정을완료했다. <project...> [ ] <dependencies> <!-- Spring Framework --> <groupid>org.springframework</groupid> <artifactid>spring-core</artifactid> <version>3.0.1.release</version> <groupid>org.springframework</groupid> <artifactid>spring-beans</artifactid> <version>3.0.1.release</version> <groupid>org.springframework</groupid> <artifactid>spring-context</artifactid> <version>3.0.1.release</version> <groupid>org.springframework</groupid> <artifactid>spring-orm</artifactid> <version>3.0.1.release</version> <!-- Struts2 Framework --> <groupid>org.apache.struts</groupid> <artifactid>struts2-core</artifactid> <version>2.1.8</version> <groupid>org.apache.struts</groupid> <artifactid>struts2-spring-plugin</artifactid> <version>2.1.8</version> <!-- IBatis Framework --> <groupid>org.apache.ibatis</groupid> <artifactid>ibatis-sqlmap</artifactid> <version>2.3.0</version> </dependencies> </project> 예제 5-3 위키북프로젝트에스트럿츠 2, 스프링, 아이바티스프레임워크에대한의존관계추가 예제 5-3 과같이의존관계를설정하고 mvn test 를실행한결과의존관계에있는라이브러리를 다운로드하고빌드가성공했다.
Maven Chapter5 Page 18 스트럿츠 2, 스프링, 아이바티스프레임워크에대한의존관계설정을끝내고빌드까지완료했는데내가설정한라이브러리를프로젝트하위디렉토리중어느곳에서도찾을수없다. 메이븐을사용하기전까지는모든라이브러리가프로젝트의특정디렉토리에포함되어있었기때문에눈으로확인할수있었다. 그런데메이븐에서는확인할수없으니어딘지모르게불안하다. pom.xml 에서확인하는것과실제 jar 파일을볼때의느낌은다르기때문이다. 의존관계로설정한라이브러리를프로젝트로복사할수있으면좋겠는데어디좋은플러그인없을까? 맞다. 2 장에서살펴봤던 Getting Started 문서 3 에서로컬저장소에있는라이브러리를프로젝트로복사했던기억이난다. mvn clean dependency:copy-dependencies package 로컬저장소에있는라이브러리를위키북프로젝트로복사하기위하여 mvn dependency:copydependencies 를실행한다. 이명령을실행하면프로젝트와의존관계에있는모든라이브러리가 target/dependency 디렉토리에복사된다. 그림 5-9 dependency:copy-dependencies 를실행한결과화면 3 http://maven.apache.org/guides/getting-started/maven-in-five-minutes.html
Maven Chapter5 Page 19 그림 5-9 를보니위키북프로젝트와의존관계에있는모든라이브러리가복사된것을확인할수있다. 그런데한가지의문점이생긴다. 앞에서설정했던 pom.xml 에서는 JUnit 라이브러리까지포함해서모두 8 개의의존관계를설정했을뿐인데그림 5-9 를보니 23 개의라이브러리가포함되어있다. 그렇다면 15 개의라이브러리는어디에서추가된것일까? 메이븐은지금까지내가학습했던내용외에또다른기능을지원하고있는것이분명하다. 이의문에대한해답을찾기위하여의존관계에대한추가적인학습이필요하다는생각이든다. 5.2.2 의존성전이 Transitive Dependency 자바기반으로애플리케이션을개발할때외부라이브러리와의의존도가어떻게변화하는지살펴보면 다음과같다. 그림 5-10 소프트웨어를개발할때외부라이브러리와의의존관계를보여주고있는그림 그림 5-10 과같이오픈소스프레임워크가추가될때마다해당프레임워크와의존관계에있는라이브러리를추가해야하기때문에하나의프로젝트가의존관계에있는라이브러리의수가증가한다. 이는결과적으로메이븐설정파일의복잡도를증가시킨다. 이같은한계점을극복하기위하여메이븐은 2.0 버전부터의존성전이기능을제공한다. 예를들어위키북프로젝트가스트럿츠 2 프레임워크와의존관계가있다. 스트럿츠 2 는프리마커 freemarker, Ognl 과의존관계에있다면위키북프로젝트는스트럿츠 2 프레임워크에대한의존관계만추가해도 프리마커, Ognl 과의존관계를가지는방식이의존성전이이다. 이예에서스트럿츠 2 프레임워크에대한설정은위키북프로젝트에서설정하고있다. 그렇다면스트럿츠 2 프레임워크가의존관계에있는라이브러리에대한설정정보는어디에있을까? 앞의 JUnit 라이브러리를다운로드할때는눈여겨봤으면그해답을찾을수있다 ( 그림 5-3). 메이븐은 jar 파일을다운로드하면서동시에 pom 파일을다운로드한다. 메이븐중앙저장소에서특정라이브러리에접근해보면모든
Maven Chapter5 Page 20 라이브러리가 pom 파일과 jar 파일을같이가지고있다. 메이븐중앙저장소에서 JUnit 4.7 버전으로 접근해보면다음과같다. 그림 5-11 중앙저장소의 JUnit 4.7 버전화면 위키북프로젝트에의존관계를설정한스트럿츠 2 프레임워크또한라이브러리를다운로드하면서 pom 파일을같이다운로드한다. 다운로드위치는같다. 스트럿츠 2 프레임워크의 struts2-core 라이브러리의 pom 파일을열어보면다음과같다. <project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelversion>4.0.0</modelversion> [...] <groupid>org.apache.struts</groupid> <artifactid>struts2-core</artifactid> <packaging>jar</packaging> <name>struts 2 Core</name> <dependencies> <groupid>com.opensymphony</groupid> <artifactid>xwork-core</artifactid> <version>2.1.6</version> <groupid>org.freemarker</groupid> <artifactid>freemarker</artifactid> <version>2.3.15</version> [...] </dependencies> </project> 예제 5-4 struts2-core 라이브러리의 pom 파일
Maven Chapter5 Page 21 예제 5-4 의 struts2-core 라이브러리의 pom 파일의내용을보면지금까지보아왔던 pom.xml 의내용과같다. 예제 5-4 는 struts2-core 라이브러리의 pom 파일일부만을보여주고있다. 실제 pom 파일을보면의존관계에있는라이브러리설정 (<dependency/> 엘리먼트설정 ) 이 10 개가훌쩍넘는다. 위키북프로젝트를빌드할때 struts2-core pom 파일에설정되어있는모든라이브러리에대한의존관계를가질경우위키북프로젝트가의존하는라이브러리수는급격하게증가할것이다. 메이븐은이같은문제점을해결하기위하여의존관계에있는라이브러리를제한하기위하여의존성 전이에대한설정이가능하도록지원하고있다. 의존성중개 Dependency mediation : 버전이다른두개의라이브러리가의존관계에있다면메이븐은더가까운의존관계에있는 pom 설정의버전과의존관계를가진다. 예를들어 A 프로젝트가 A -> B -> C -> D 2.0 버전, A -> E -> D 1.0 버전으로의존관계가발생한다면 A 프로젝트는 D 1.0 버전과의존관계를가진다. 만약 D 2.0 버전을사용하고싶다면 A 프로젝트의메이븐설정파일에명확하게의존관계를명시해야한다. 의존성관리 Dependency management : 이기능은메이븐설정파일의 <dependencymanagement/> 엘리먼트에의존관계에있는라이브러리와버전을명시적으로정의한다. 앞의예에서 A 프로젝트에서 D 라이브러리의 2.0 버전을사용한다고 <dependencymanagement/> 에설정할수있다. 이기능에대한더자세한내용은 12 장에서다루도록하겠다. 의존성스코프 Dependency scope : 현재빌드의상태에맞는라이브러리인경우의존관계를가진다. 예를 들어 test 스코프를가지는경우최종배포산출물을빌드하는시점에는포함되지않는다. 의존성예외 Excluded dependencies : 의존관계에있는라이브러리를 <exclusion/> 엘리먼트를활용하여 명시적으로제외시킬수있다. 선택적의존성 Optional dependencies : A -> B -> C 와같은구조로의존관계를가지는경우 B 프로젝트에 C 가 optional 로설정되어있다면 A 프로젝트를빌드할때 C 는의존관계를가지지않도록 설정하는기능이다. 이설정은 <optional/> 엘리먼트를활용하여설정하는것이가능하다. 메이븐이의존성전이기능을제공하기때문에불필요한라이브러리가추가되거나의도하지않는 라이브러리와의존관계를가지게된다. 이같은문제가발생할경우위 5 가지기능을활용하여불필요한 라이브러리가프로젝트에포함되지않도록설정해야한다. 위기능을활용하여앞에서설정한위키북프로젝트에서필요없는의존관계에대한설정을제거해보자. 가장먼저제거하면좋겠다고생각하는라이브러리는 commons-io-1.3.2.jar 에대한의존관계이다. 이 라이브러리에대한의존관계를제거하려면먼저 commons-io-1.3.2.jar 라이브러리가어떤라이브러리에서
Maven Chapter5 Page 22 의존성전이가된것인지를파악해야한다. commons-io-1.3.2.jar 라이브러리에대한의존성전이를일으킨라이브러리는어떻게찾을수있을까? 가장쉽지만무식한방법은위키북프로젝트에서 <dependency/> 엘리먼트에설정되어있는모든라이브러리의 pom 파일을다운로드해열어보면서일일이확인하는방법이다. 의존라이브러리가 4,5 개정도라면이방법으로도가능할수있겠지만대부분의프로젝트가 10 개를훌쩍넘어가는상황에서는사용할수없는방법이다. 이같은문제를해결하기위하여메이븐의 dependency 플러그인은현재프로젝트와의존관계에있는라이브러리의구조를파악할수있도록 tree 골을제공하고있다. 앞에서생성한위키북프로젝트에서 mvn dependency:tree 를실행해보자. 그림 5-12 위키북프로젝트에서 dependency:tree 를실행한화면 그림 5-12 를보면위키북프로젝트와의존관계에있는라이브러리를트리 tree 구조로한눈에확인할수 있다. 제거하고싶은 commons-io-1.3.2.jar 에대한의존관계는 struts2-core 라이브러리가가진다. 따라서 struts2-core 라이브러리설정에서의존성예외기능을활용하여명시적으로제외시킨다.
Maven Chapter5 Page 23 <groupid>org.apache.struts</groupid> <artifactid>struts2-core</artifactid> <version>${struts2.verion}</version> <exclusions> <exclusion> <groupid>commons-io</groupid> <artifactid>commons-io</artifactid> </exclusion> </exclusions> 이같은과정을반복해위키북프로젝트에서반드시필요한라이브러리만의존관계를가지도록설정할수 있다. 앞에서잠시언급했지만 struts2-core 라이브러리의 POM 설정파일은 10 개이상의라이브러리와의존관계를가진다. 그럼에도불구하고그림 5-12 에서최종적으로의존관계를가지는라이브러리는 6 개이다. 그이유는 struts2-core pom 파일에설정되어있는대부분의라이브러리는의존성스코프와선택적의존성설정때문이다. 예를들면다음과같다. <groupid>javax.servlet</groupid> <artifactid>servlet-api</artifactid> <version>2.4</version> <scope>provided</scope> <groupid>org.springframework</groupid> <artifactid>spring</artifactid> <version>${struts2.springplatformversion}</version> <scope>compile</scope> <optional>true</optional>
Maven Chapter5 Page 24 이와같이의존성스코프와선택적의존성기능을활용하여의존관계를관리하도록설정하고있기때문에 위키북프로젝트에서최종적으로의존관계에있는라이브러리는최소한으로제한된다. 5.2.3 의존성스코프와의존성전이와의관계 의존성스코프는단순히라이브러리에대한의존성스코프만을정의하는것이아니라의존성전이와 관련이있다. 의존성스코프와의존성전이관계는다음표를통하여확인할수있다. 표 5-1 의존성스코프와의존성전이와의관계 직접적인의존관계 라이브러리의 스코프 의존성전이에있는라이브러리의스코프 compile provided runtime test compile compile - runtime - provided provided provided provided - runtime runtime - runtime - test test - test - 표 5-1 의좌측행의값은프로젝트와직접적으로의존관계를가지는라이브러리의스코프이고, 위열의 값은의존성전이상태에있는라이브러리의스코프이다. 예를들어 A 프로젝트는 B 라이브러리에대하여 compile 스코프로의존관계를가지며, B 라이브러리는 C 라이브러리와 runtime 스코프로의존관계를가지는상태이다. 이때 A 프로젝트는 C 라이브러리에대하여 runtime 스코프로의존관계를가지게된다. 표 5-1 에서스코프값으로표시되지않고 - 로표시되어있는상태라면의존성전이상태에서해당라이브러리를제외된다. 예를들어프로젝트 A -> B 는 compile 스코프, B -> C 는 provided 스코프라면 A 프로젝트는 C 라이브러리와의존관계를가지지않게된다.
Maven Chapter5 Page 25 5.3 속성 properties 메이븐의의존라이브러리관리기능에대하여공부한오전만하더라도이기능이예상한것보다쉽다는생각이었다. 그런데위키북프로젝트에의존관계설정을하면서의존라이브러리관리기능에대하여알지못했던새로운기능들을많이알게되었다. 특히의존성전이기능은의존관계의효율적인관리를위하여반드시필요한기능이라고생각하는데그로인해발생하는부작용도많겠다는생각이든다. 의존성전이기능에서발생하는문제점을해결하기위한방법이복잡하지만이방법을명확히이해하고사용할경우효율적인의존관계설정이가능하리라. 위키북프로젝트의의존관계를마무리하려고설정파일을살펴보니스트럿츠 2 와스프링프레임워크버전 정보가중복되고있다. 빌드설정을하면서중복되는설정정보가많이발생할텐데이부분에대한중복을 제거해야겠다. 메이븐은설정파일에서발생하는중복설정을제거하기위하여속성 (<properties/> 엘리먼트 ) 을정의하고 설정파일전체에서사용할수있다. 예를들어앞에서설정한위키북프로젝트의스트럿츠 2, 스프링 프레임워크의의존관계에서발생하는중복을제거하려면다음과같이설정할수있다. <project> [ ] <properties> <struts2.verion>2.1.8</struts2.verion> <spring.verion>3.0.1.release</spring.verion> </properties> <dependencies> <!-- Spring Framework --> <groupid>org.springframework</groupid> <artifactid>spring-core</artifactid> <version>${spring.verion}</version> <groupid>org.springframework</groupid> <artifactid>spring-beans</artifactid> <version>${spring.verion}</version> <!-- Struts2 Framework --> <groupid>org.apache.struts</groupid> <artifactid>struts2-core</artifactid> <version>${struts2.verion}</version> [ ] </project> 예제 5-5 스트럿츠 2, 스프링프레임워크의버전정보를속성기능을활용하도록리팩토링
Maven Chapter5 Page 26 메이븐에서속성은예제 5-5 처럼 <properties /> 엘리먼트에서 <property.name>value</property.name> 같은형태로정의한다. <properties/> 엘리먼트에정의한속성은 pom.xml 파일내에서 ${property.name} 로접근한다. 예제 5-5 에서사용한속성은개발자가정의해서사용할수있는속성이다. 이외에도메이븐은미리예약되어있는속성이있다. 메이븐에서미리예약되어사용할수있는속성은 pom/project 속성, settings 속성, 환경변수속성, 자바시스템속성이다. 5.3.1 pom/project 속성 pom.xml 파일의엘리먼트에서설정한정보는 project 와 pom 을접두사로사용하여참조할수있다. pom 접두사는메이븐 3.0 에서 deprecated 되는속성이기때문에가능하면 project 접두사를사용하는것이 바람직한선택이다. 몇가지예를들어보면다음과같다. ${project.build.directory} 는 "target" 디렉토리이다. 이속성은 ${pom.build.directory} 와같다. ${project.build.outputdirectory} 는 "target/classes" 디렉토리이다. ${project.name}, ${pom.name} 는프로젝트이름이다. <project>/<name> 엘리먼트설정값. ${project.version}, ${pom.version} 는프로젝트버전이다. 버전정보는접두사를사용하지않고 ${version} 으로도접근가능하다. <project>/<version> 엘리먼트설정값. ${project.build.finalname} 는 package 페이즈를실행해압축된최종파일이름이다. <project>/<build>/<finalename> 엘리먼트설정값 5.3.2 settings 속성 메이븐과관련한설정은 settings.xml 파일에서한다. 이 settings.xml 파일에서정의한설정값을참조할수 있는것이 settings 속성이다. settings 속성은 settings 접두사를사용한다. ${settings.localrepository} 는로컬저장소의경로를참조한다. 5.3.3 환경변수속성 메이븐은 env 접두사를이용하여시스템환경변수의값을참조할수있다.
Maven Chapter5 Page 27 ${env.path} 는시스템의 PATH 설정값을참조한다. ${env.java_home} 은시스템의 JAVA_HOME 설정값을참조한다. 5.3.4 자바시스템속성 메이븐은자바시스템속성으로설정된모든속성을참조할수있다. 자바시스템속성은 http://leepoint.net/notes-java/io/30properties_and_preferences/40sysprops/10sysprop.html 문서에서 참고할수있다. 위 4 가지에포함되지않지만자주사용하는속성중의하나는 ${basedir} 이다. ${basedir} 속성은 pom.xml 설정파일이위치하는디렉토리이다. 메이븐의속성기능을이용하여중복이발생하는부분에대한정리작업까지모두완료했다. 중복을제거한후나머지의존관계에대한설정작업을진행했다. 그런데무슨라이브러리가필요할지명확하지않았다. 따라서현시점에명확하게필요하다고생각하는 log4j, commons-dbcp, mysql jdbc driver 라이브러리에대한의존관계설정까지추가하고완료하였다. 프로젝트초반에필요한모든라이브러리에대한의존관계설정을완료하기는힘들다. 따라서내가세운전략은프로젝트초반에는현시점에결정할수있는의존관계설정까지진행하고프로젝트를진행하면서추가적으로설정하기로했다. 초반부터너무많은부분을결정하기보다는결정할수있는순간에결정하는전략을취하기로했다. 스트럿츠 2, 스프링, 아이바티스프레임워크에대한의존라이브러리설정까지마쳤으니위키북프로젝트에기능을추가하는작업을진행할수있겠다. 그런데모든개발은이클립스통합개발환경에서진행하고있는상황이라지금까지만든프로젝트를이클립스에서개발이가능한상태로만들어야겠다. 오늘은메이븐의의존라이브러리관리기능을이해하고, 위키북프로젝트에의존관계에있는모든프레임워크설정을마칠수있어즐거웠는데또한가지해결해야할숙제가남았다. 역시새로운툴을도입하는데있어한번에해결되는것은없다. 다음단계로는이클립스에서위키북프로젝트를진행할수있도록개발환경을설정하는방법에대하여살펴봐야겠다.
Maven Chapter5 Page 28 6. 메이븐과이클립스통합 7. 메이븐과데이터베이스통합 8. 메이븐프로파일, 배포 9. 리포팅기능을활용한문서관리 10. 메이븐모듈 module 11. 메이븐사내저장소설치및활용 12. 표준 POM 파일생성및리팩토링 13. 메이븐아키타입 archetype 14. 새로운프로젝트를시작하면서..