หลังจากผ่านสมรภูมิการแปลง java project ซึ่งเป็น library ที่ที่ทำงานใช้กันมากว่า 5 ปี ของเดิมใช้ ant script ตอนนี้อยากจะใช้มันแบบ maven ถึงจะช้าแต่ก็ดีกว่าไม่ทำนะ ;) เลยมาบันทึกเอาไว้หน่อยว่า สิ่งที่ทำบ่อยๆ ตอนนั้นมีอะไรบ้าง
ใช้ mvn dependency:analyze
เพื่อตรวจสอบ dependency สำหรับ project เราว่า
- เราประกาศตัวที่ใช้ (ใส่ dependency) ครบหรือยัง (Used undeclared dependencies)
- เราเผลอประกาศตัวไหนที่ไม่ได้ใช้ลงไปใน pom หรือเปล่า (Unused declared dependencies)
ตัวอย่าง
...
[INFO] --- maven-dependency-plugin:2.8:analyze (default-cli) @ example-core ---
[WARNING] Used undeclared dependencies found:
[WARNING] org.springframework:spring-core:jar:3.1.1.RELEASE:compile
[WARNING] org.springframework:spring-beans:jar:3.1.1.RELEASE:compile
[WARNING] Unused declared dependencies found:
[WARNING] org.springframework:spring-test:jar:3.1.1.RELEASE:compile
[WARNING] org.slf4j:slf4j-log4j12:jar:1.7.0:compile
[WARNING] log4j:log4j:jar:1.2.14:compile
...
หากเห็น Used undeclared dependencies found
ในผลลัพธ์ ควรจะกลับมาประกาศ dependency นั้นใน pom
หากเจอ Unused declared dependencies
เราอาจจะเปลี่ยน scope ของ dependency ให้เหมาะสม หรือไม่จำเป็นต้องประกาศ เช่น org.springframework:spring-test:jar:3.1.1.RELEASE:compile
เราเปลี่ยน scope เป็น test
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.1.1.RELEASE</version>
<scope>test</scope>
</dependency>
การเอา dependency ออก แนะนำให้ comment เอาไว้ก่อน แล้วทดสอบ compile หรือ package ดู หากมี unit test อยู่ เราจะรู้ได้ทันทีว่า เราจะเอามันออกได้หรือไม่ ถ้าไม่ได้แสดงว่าเราควรเปลี่ยน scope ของมัน
ใช้ mvn dependency:tree
อยากตรวจสอบว่า jar แต่ละตัวมีความสัมพันธ์ต่อกันอย่างไร
$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] Building Example 1.1
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ example-web ---
[INFO] com.example:example-web:jar:1.1
[INFO] +- javax.servlet:servlet-api:jar:2.5:provided
[INFO] +- org.springframework:spring-context:jar:3.1.1.RELEASE:compile
[INFO] | +- org.springframework:spring-aop:jar:3.1.1.RELEASE:compile
[INFO] | +- org.springframework:spring-expression:jar:3.1.1.RELEASE:compile
[INFO] | \- org.springframework:spring-asm:jar:3.1.1.RELEASE:compile
[INFO] +- org.springframework:spring-core:jar:3.1.1.RELEASE:compile
[INFO] +- org.springframework:spring-beans:jar:3.1.1.RELEASE:compile
[INFO] +- org.springframework:spring-web:jar:3.1.1.RELEASE:compile
[INFO] | \- aopalliance:aopalliance:jar:1.0:compile
[INFO] +- org.springframework:spring-webmvc:jar:3.1.1.RELEASE:compile
[INFO] | \- org.springframework:spring-context-support:jar:3.1.1.RELEASE:compile
[INFO] +- javax.persistence:com.springsource.javax.persistence:jar:2.0.0:compile
[INFO] +- org.eclipse.persistence:javax.persistence:jar:2.0.0:compile
[INFO] +- org.freemarker:freemarker:jar:2.3.18:compile
[INFO] +- commons-io:commons-io:jar:1.4:compile
[INFO] +- javax.validation:validation-api:jar:1.0.0.GA:compile
[INFO] +- commons-beanutils:commons-beanutils:jar:1.7.0:compile
[INFO] | \- commons-logging:commons-logging:jar:1.0.3:compile
[INFO] +- junit:junit:jar:4.10:compile
[INFO] | \- org.hamcrest:hamcrest-core:jar:1.1:compile
[INFO] +- net.sourceforge.json:com.springsource.net.sf.json:jar:2.2.2:compile
[INFO] | +- org.apache.commons:com.springsource.org.apache.commons.beanutils:jar:1.7.0:compile
[INFO] | +- org.apache.commons:com.springsource.org.apache.commons.collections:jar:3.2.0:compile
[INFO] | +- org.apache.commons:com.springsource.org.apache.commons.logging:jar:1.1.1:compile
[INFO] | \- net.sourceforge.ezmorph:com.springsource.net.sf.ezmorph:jar:1.0.5:compile
[INFO] +- org.apache.commons:com.springsource.org.apache.commons.lang:jar:2.5.0:compile
[INFO] +- org.hibernate:com.springsource.org.hibernate.validator:jar:4.1.0.GA:compile
[INFO] | \- javax.validation:com.springsource.javax.validation:jar:1.0.0.GA:compile
[INFO] +- org.mockito:com.springsource.org.mockito:jar:1.8.4:compile
[INFO] | +- org.objenesis:com.springsource.org.objenesis:jar:1.2.0:compile
[INFO] | \- org.hamcrest:com.springsource.org.hamcrest.core:jar:1.1.0:compile
[INFO] +- org.slf4j:slf4j-api:jar:1.7.0:compile
[INFO] +- org.slf4j:slf4j-log4j12:jar:1.7.0:compile
[INFO] +- log4j:log4j:jar:1.2.14:compile
[INFO] +- com.example:example-persistence:jar:1.1:compile
[INFO] | +- org.springframework:spring-tx:jar:3.1.1.RELEASE:compile
[INFO] | +- org.springframework:spring-jdbc:jar:3.1.1.RELEASE:compile
[INFO] | +- org.springframework:spring-orm:jar:3.1.1.RELEASE:compile
[INFO] | +- org.springframework:spring-test:jar:3.1.1.RELEASE:compile
[INFO] | +- javax.transaction:transaction-api:jar:1.1:compile
[INFO] | +- org.hibernate:com.springsource.org.hibernate:jar:3.3.2.GA:compile
[INFO] | | +- net.sourceforge.cglib:com.springsource.net.sf.cglib:jar:2.2.0:compile
[INFO] | | +- org.antlr:com.springsource.antlr:jar:2.7.6:compile
[INFO] | | +- org.dom4j:com.springsource.org.dom4j:jar:1.6.1:compile
[INFO] | | +- org.jboss.javassist:com.springsource.javassist:jar:3.9.0.GA:compile
[INFO] | | +- org.objectweb.asm:com.springsource.org.objectweb.asm:jar:1.5.3:compile
[INFO] | | \- org.slf4j:com.springsource.slf4j.api:jar:1.5.6:compile
[INFO] | +- org.hibernate:hibernate-annotations:jar:3.4.0.GA:compile
[INFO] | | +- org.hibernate:ejb3-persistence:jar:1.0.2.GA:compile
[INFO] | | +- org.hibernate:hibernate-commons-annotations:jar:3.1.0.GA:compile
[INFO] | | +- org.hibernate:hibernate-core:jar:3.3.0.SP1:compile
[INFO] | | \- dom4j:dom4j:jar:1.6.1:compile
[INFO] | | \- xml-apis:xml-apis:jar:1.0.b2:compile
[INFO] | +- commons-dbcp:commons-dbcp:jar:1.2.2:compile
[INFO] | | \- commons-pool:commons-pool:jar:1.3:compile
[INFO] | +- org.aspectj:aspectjweaver:jar:1.6.5:compile
[INFO] | +- org.slf4j:slf4j-jcl:jar:1.4.2:compile
[INFO] | +- org.hsqldb:hsqldb:jar:1.8.0.10:compile
[INFO] | \- org.dbunit:dbunit:jar:2.2:compile
[INFO] | +- junit-addons:junit-addons:jar:1.4:compile
[INFO] | | +- xerces:xercesImpl:jar:2.6.2:compile
[INFO] | | \- xerces:xmlParserAPIs:jar:2.6.2:compile
[INFO] | +- poi:poi:jar:2.5.1-final-20040804:compile
[INFO] | +- commons-collections:commons-collections:jar:3.1:compile
[INFO] | \- commons-lang:commons-lang:jar:2.1:compile
[INFO] +- com.example:example-template:jar:1.1:compile
[INFO] \- com.example:example-core:jar:1.1:compile
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.783 s
[INFO] Finished at: 2016-02-11T10:13:10+07:00
[INFO] Final Memory: 13M/309M
ใช้ property มาช่วยให้การประกาศ dependency สะอาดตา และ maintain ง่ายขึ้น
เช่น หากต้องประกาศ spring-*** เยอะขนาดนี้ จะเห็นว่ามี 3.1.1.RELEASE
ซ้ำๆกันเต็มไปหมด
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.1.1.RELEASE</version>
<scope>test</scope>
</dependency>
เราสามารถจะทำแบบนี้ได้ ประกาศเลข version ใน properties tag เวลาจะเปลี่ยน version ก็มาแก้ไขที่นี่ที่เดียว ครั้งเดียวด้วย
<properties>
...
<spring.framework.version>3.1.1.RELEASE</spring.framework.version>
</properties>
แล้วเอา ${spring.framework.version}
มาแทนที่ 3.1.1.RELEASE
ในส่วนที่ประกาศ dependency
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.framework.version}</version>
<scope>test</scope>
</dependency>
ศึกษาเพิ่มเติม kyleblaney’s maven best practice