原文: http://my.oschina.net/xuqiang/blog/99854
本文介紹一個多maven項目的實例demo,展示了聚合、繼承、工程依賴、單元測試、多war聚合、cargo發布等場景
一、工程介紹
該項目由5個maven項目組成
task-aggregator是父工程,同時承擔聚合模塊和父模塊的作用,沒有實際代碼和資源文件 task-common是基礎工程,里面是公共的代碼 task-sla是某一個業務子模塊,不包含web內容 task-sla-web是某一個web子模塊 task-web-dist是最外圍的web工程,聚合多個web工程,形成最終的war包
依賴關系是:task-common <-- task-sla <-- task-sla-web <-- task-web-dist
二、task-aggregator
這個工程是起到聚合作用,並充當parent pom,所以沒有任何實際代碼和資源文件。我這里選擇了平行結構,另外一種方式是樹形結構,我個人感覺平行結構看起來更舒服一點
下面是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/xsd/maven-4.0.0.xsd">
- <!-- 定義公共變量 -->
- <properties>
- <spring.version>3.1.0.RELEASE</spring.version>
- <struts2.version>2.3.1</struts2.version>
- <hibernate.version>3.2.7.ga</hibernate.version>
- </properties>
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.huawei.inoc.wfm.task</groupId>
- <artifactId>task-aggregator</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <packaging>pom</packaging>
- <!-- 待聚合模塊 -->
- <modules>
- <module>../task-common</module>
- <module>../task-sla</module>
- <module>../task-sla-web</module>
- <module>../task-web-dist</module>
- </modules>
- <!-- 配置部署的遠程倉庫 -->
- <distributionManagement>
- <snapshotRepository>
- <id>nexus-snapshots</id>
- <name>nexus distribution snapshot repository</name>
- <url>http://10.78.68.122:9090/nexus-2.1.1/content/repositories/snapshots/</url>
- </snapshotRepository>
- </distributionManagement>
- <build>
- <pluginManagement>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-resources-plugin</artifactId>
- <version>2.6</version>
- <configuration>
- <encoding>UTF-8</encoding>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <version>2.5.1</version>
- <configuration>
- <encoding>UTF-8</encoding>
- </configuration>
- </plugin>
- </plugins>
- </pluginManagement>
- </build>
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>com.sun</groupId>
- <artifactId>tools</artifactId>
- <version>1.6.0</version>
- <scope>system</scope>
- <systemPath>${env.JAVA_HOME}/lib/tools.jar</systemPath>
- </dependency>
- </dependencies>
- </dependencyManagement>
- </project>
基本上是一目了然,只是有幾點注意下:
1、這里配置了<distributionManagement>,這樣子項目就不需要重復配置了
2、通過<pluginManagement>,對一些插件進行了公共的配置,這里主要是為了消除構建時的告警
3、配置tools,是因為實際中發現,其他開發人員從svn上check out工程以后,有的人會報錯,找不到tools.jar,這樣配置以后就好了
三、task-common
該工程是公共工程,提供了項目中的公共代碼,這里只包括了通用的DAO組件,作為示例。
該工程不依賴任何其他工程
該工程里有幾點要點:
1、在代碼內部用了Spring的注解
- public abstract class GenericDAO<T> implements IGenericDAO<T> {
- private Class<T> entityClass;
- public GenericDAO(Class<T> clazz) {
- this.entityClass = clazz;
- }
- @Autowired
- private HibernateTemplate hibernateTemplate;
- }
這里用到了@Autowired注解,所以最終形成的war包,必須在spring配置文件中聲明HibernateTemplate類型的bean,否則會報錯
我這里用的maven環境是maven3.0.4,這個版本打出的jar包,帶有Directory Entries信息,所以spring的注解即使在jar包中也可生效,如果是比較老的版本,spring的注解在jar包中不好用,關於這個問題的詳細描述,見另外一篇博客:http://kyfxbl.iteye.com/blog/1675368
2、單元測試的寫法
- @RunWith(SpringJUnit4ClassRunner.class)
- @ContextConfiguration(locations = "classpath:spring-test.xml")
- @Transactional
- public class GenericDAOTest {
- @Autowired
- private IBookDAO bookDAO;
- @Test
- public void testInsert() {
- Book book = new Book();
- book.setName("thinking in java");
- book.setIsbn("111");
- bookDAO.insert(book);
- }
- }
這里用到了幾個注解,@RunWith是為了在spring容器環境下跑這個單元測試類,以支持依賴注入。@ContextConfiguration是聲明spring配置文件的位置。@Transactional注解之后,在單元測試方法中的事務會自動回滾,這個比較方便,這樣在前面執行的方法,不會對后面的方法造成影響
這個單元測試類,可以直接在maven里跑起來,讓我比較驚喜。之前這樣寫,在ant里跑沒有成功,可能是我沒有找到合適的插件的原因
3、除了測試的java代碼之外,還有3個資源文件,都是放在src/test/resources下,這些資源文件只在test階段生效,package階段不會被打包,也就是專門供測試階段使用
這個各有利弊,優點是測試的配置文件與開發的配置文件隔離,互不干擾。缺點是配置文件似乎缺少了集中放置的地點,這樣如果多個maven工程都需要跑單元測試,要共享測試用配置文件,比較麻煩一點
不過從我個人來看,也算是利大於弊。只是在每個maven項目下,都需要獨立的測試相關資源文件,其實也有利於分別修改
另外,可以看到這里的hibernate映射文件,不是和model類放在一個package下,而是放在resources目錄下的,這樣做可以避免一些潛在的問題,也有利於后續的聚合
4、pom文件沒有什么特別的,只是要引入<scope>為test的junit和spring-test
四、task-sla
該工程依賴task-common(因為用到了GenericDAO),是某一個業務模塊的邏輯部分,包含了數據庫訪問層和業務邏輯層,但是不包括web相關的部分
這里沒有什么特別要注意的,目錄結構和task-common基本一樣。比較特別的是可以看到Maven Dependencies里,有一個task-common工程,所以task-common里的任何修改,都可以第一時間在這個工程里體現出來,是比較方便的
關於這個問題,見另外一篇博客:http://kyfxbl.iteye.com/blog/1679806
另外就是前面說過的,hibernate的映射文件,應該放在src/main/resources下,而不是與Model類放在一起
五、task-sla-web
這個工程是上述task-sla工程的web層,依賴於task-sla,由於task-sla又依賴task-common,所以這個工程最終會同時依賴task-common和task-sla
然后這個工程里包含了web層的東西,包括Action類、jsp、圖片、struts2的配置文件等,這些東西放在web工程里是最合適的
這里需要注意2點:
1、這個工程的packaging類型是war,而不是jar。但是最終它不會獨立打出war包來,其src/main/webapp里的所有文件,都會被最外圍的task-web-dist工程聚合成一個總的war
2、這個工程的WEB-INF目錄下,沒有web.xml(有也沒用,最終會被覆蓋)。默認情況下,packaging類型為war的項目,如果沒有web.xml,則構建會失敗,因此需要在pom里做一個配置
該項目的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">
- <parent>
- <groupId>com.huawei.inoc.wfm.task</groupId>
- <artifactId>task-aggregator</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <relativePath>../task-aggregator</relativePath>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>task-sla-web</artifactId>
- <packaging>war</packaging>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-war-plugin</artifactId>
- <configuration>
- <failOnMissingWebXml>false</failOnMissingWebXml>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <!-- 配置依賴 -->
- <dependencies>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-beans</artifactId>
- </dependency>
- </dependencies>
- </project>
上面的<failOnMissingWebXml>,就是配置缺少web.xml也不使構建失敗
六、task-web-dist
這個工程是最外圍的web工程,起到聚合的作用,即把所有的web項目,打成最終的war包。同時,在這個工程里,放置里公共的配置文件,比如struts.xml、ssoconfig.properties等
這個工程的聚合意圖十分明顯,比如struts.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd">
- <struts>
- <constant name="struts.objectFactory" value="spring" />
- <constant name="struts.ui.theme" value="simple" />
- <constant name="struts.i18n.encoding" value="UTF-8" />
- <constant name="struts.action.extension" value="action" />
- <constant name="struts.enable.DynamicMethodInvocation" value="false" />
- <constant name="struts.devMode" value="true" />
- <include file="struts2/struts-sla.xml" />
- </struts>
提供了項目通用的配置,並把各子項目的struts2配置文件聚合起來。war包中的web.xml也是在這里提供的
下面是該工程的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">
- <parent>
- <groupId>com.huawei.inoc.wfm.task</groupId>
- <artifactId>task-aggregator</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <relativePath>../task-aggregator</relativePath>
- </parent>
- <modelVersion>4.0.0</modelVersion>
- <artifactId>task-web-dist</artifactId>
- <packaging>war</packaging>
- <build>
- <finalName>task</finalName>
- <plugins>
- <!-- 合並多個war -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-war-plugin</artifactId>
- <configuration>
- <packagingExcludes>WEB-INF/web.xml</packagingExcludes>
- <overlays>
- <overlay>
- <groupId>com.huawei.inoc.wfm.task</groupId>
- <artifactId>task-sla-web</artifactId>
- </overlay>
- </overlays>
- </configuration>
- </plugin>
- <!-- 利用cargo啟動容器 -->
- <plugin>
- <groupId>org.codehaus.cargo</groupId>
- <artifactId>cargo-maven2-plugin</artifactId>
- <version>1.2.3</version>
- <configuration>
- <container>
- <containerId>tomcat7x</containerId>
- <home>D:\apache-tomcat-7.0.29</home>
- </container>
- <configuration>
- <type>standalone</type>
- <home>${project.build.directory}/tomcat7.0.29</home>
- <properties>
- <cargo.jvmargs>
- -Xdebug
- -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787
- </cargo.jvmargs>
- </properties>
- </configuration>
- </configuration>
- <executions>
- <execution>
- <id>cargo-run</id>
- <phase>pre-integration-test</phase>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- </project>
這里主要是對maven-war-plugin和cargo-maven2-plugin這2個插件進行了配置,以起到聚合war,以及通過cargo啟動容器的作用
關於多war聚合,以及cargo,見另外2篇博客:http://kyfxbl.iteye.com/blog/1678121、http://kyfxbl.iteye.com/blog/1677608
七、啟動構建
在task-aggregator目錄下,執行mvn clean deploy或者mvn clean install,就可啟動整個構建過程,並將容器啟動起來,跑最終生成的war包
最后分享一個笑話緩解下工作壓力:
https://kuaibao.qq.com/s/20181119A1X9SQ00?refer=kb_news&coral_uin=ecbc9744e6bf83a8ee79eafb517233e109d8b12d0b4850642b13a6d813a8da84aa&omgid=36f498806541f5e72eaf068466e0d98a