Monthly Archives: January 2012

《Maven实战》笔记 5.2 – 继承

继承是为了实现“在父项目里声明,在各个子项目里使用”,比如项目的版本、项目的groupId、依赖等。

下面是项目module-base的pom.xml的片段

        <!--module-base将继承module-root-->
        <parent>
                <groupId>mvn-module</groupId>
                <artifactId>module-root</artifactId>
                <version>1.0.0-SNAPSHOT</version>
                <relativePath>../pom.xml</relativePath>
        </parent>

        <!--这里不必再显式声明groupId和version。项目会自动从父项目中继承-->
        <artifactId>module-base</artifactId>

========================================

Super Pom

  java中每个类都是java.lang.Object的子类,maven中每个项目的pom都是Super Pom的子pom. Super Pom是Maven内置的顶级Pom,Maven项目的默认目录结构就是在这里定义的。

=========================================

对“依赖”的继承是最主要的用处之一。最佳实践是:

1. 父项目的pom.xml通过<dependencyManagement>声明所有会用到的dependency

2. 子项目的pom.xml通过<dependencies>声明所需的依赖。声明中不需要指明所依赖的构件的版本。

说明:

1.为什么要在父项目的pom中集中声明所有依赖? 因为这样可以保证,对同一个构件,所有子项目都会使用相同的版本。

2.为什么父项目中要用<dependencyManagement>而不直接用<dependencyies> ? 因为如果用后者,其中定义的dependency会被所有子项目继承,子项目在打包时会把这些构件打在自己的包中,即使这个子项目并不需要某些dependency.

《Maven实战》笔记 5.1 – aggregation

Maven项目大了,就要拆成多个小项目。这就是aggregation要干的事。

具体来说,就是要在各个小项目建好之后,再建一个专们用于聚合的项目。在这个项目的pom.xml里声明:


        <!--此类项目的打包方式必须为pom-->
        <packaging>pom</packaging>
        <!--在这里声明小项目-->
        <modules>
                <!--module-base, module-app是小项目的目录名-->
                <module>module-base</module>
                <module>module-app</module>
        </modules>

对这个项目执行一下"mvn package", Maven会自动构建小项目module-base 和 module-app

如果执行"mvn package
-pl module-base",则Maven只构建module-base

《Maven实战》笔记 4.2 – maven命令与lifecycle&plugin的关系

  mvn test

  执行lifecycle "default"的phase "test". 由于phase "test"被绑定到surefire plugin的test goal, 因此surefire的test goal会被执行; 同时, phase "test"之前的所有的phase也会被执行。

  mvn eclipse:eclipse

  执行 eclipse plugin中的eclipse goal. "eclipse" plugin是哪个plugin? 如果没有特殊配置,Maven会去
http://repo1.maven.org/maven2/org/apache/maven/plugins/maven-metadata.xml等默认metadata中寻找prefix=eclipse的配置

《Maven实战》笔记 4.1 – lifecycle和plugin的概念

a.Maven定义了标准的lifecycle,如 编译 -> 测试 -> 打包,每个步骤称作一个"phase"。phase有先后关系,执行一个phase前必须先执行前面所有的phase

b.phase有名无实,只是一个虚的接口,本身并不做任何事情

c.plugin则做一些真正的事情,比如真正的编译、打包等。一个插件可以有多个功能点,每个功能点称作一个"goal"

d.把phase 和 goal关联起来,就可以基于lifecycle进行构建了

《Maven 实战》笔记3.3 – internal repository与mirror

    internal repository是指在局域网内部搭建的repository,它跟central repository, jboss repository等的区别仅仅在于其URL是一个内部网址

    mirror则相当于一个代理,它会拦截去指定的远程repository下载构件的请求,然后从自己这里找出构件回送给客户端。配置mirror的目的一般是出于网速考虑。

    可以看出,
internal repository和mirror是两码事。前者本身是一个repository,可以和其它repository一起提供服务,比如它可以用来提供公司内部的maven构件;而后者本身并不是repository,它只是远程repository的网络加速器。

    不过,很多internal repository搭建工具往往也提供mirror服务,比如Nexus就可以让同一个URL,既用作internal repository,又使它成为所有repository的mirror

《Maven 实战》笔记3.2 – 让Repository区别对待snapshot版本和release版本

可以让Repository区别对待snapshot版本和release版本。也就是说,你可以只从jboss repository中下载release版本,并只从google repository中下载snapshot版本。

     另外,考虑到本地Repository相当于远程Repository的缓存,应该设置一下缓存的更新频率,提供snapshot的repository更要设置(当然,也可以不显式设置,默认值是daily)

    

  

            <repository>
             <!-- ... -->
     			  <releases>
     			        <!-- 本repository不提供release版本下载 -->
			            <enabled>false</enabled>			             		        	    
		          </releases>
			      <snapshots>
					    <!-- 本repository提供snapshot版本下载 -->
			            <enabled>true</enabled>
			            <!-- 缓存每超过五分钟就要更新--> 
			            <updatePolicy>5</updatePolicy>
		          </snapshots>
             <!-- ... -->
 
   
    

  

《Maven 实战》笔记3.1 – Repository的概念及其在项目中的使用

1. Repository用来存放maven项目的构件,如pom, *.jar, *-source.jar等,它的布局像一个文件系统,有路径(目录)和文件

2. 使用Maven时,你会跟两类Repository打交道。

   a. 存放在你本机那些的构件即组成“
本地Repository

   b. 不在你本机的、存在服务器上的叫“
远程Repository"。

   当Maven需要构件时,首先会在本地Repository里找,找不到才去远程Repository中找。

3. Repository是相对于项目而言的,所以
你可以在项目级别配置远程的Repository,而且可以配多个。

   一个Repository是一个 id + url + 其它信息的组合。id你可以随便取,url则是远程Repository的确切地址。

<project>
	<repositories>
		<repository>
			<id>jboss</id>
		        <name>jboss</name>
			<url>https://repository.jboss.org/nexus/content/repositories/</url>
		    ...
		</repository>
		
		<repository>
			<id>google</id>
		        <name>google</name>
			<url>http://google-maven-repository.googlecode.com/svn/repository/</url>
		    ...
		</repository>		
	</repositories>     
...
</project>

对此你可能有多种疑问:

问:项目里配了两个repository,那下载构件时,Maven去哪个repository呢?

答案:测试表明,Maven会先去定义在最前面的repository即"jboss"里去找; 如果找不到,再去"google"找

问:如果jboss和google里都找不到呢?

答:就去Maven默认的central repository里去找,它的id是"central", url是http://repo1.maven.org/maven2. 这个配置写死在maven的某个jar里面

问:如果我把上面的jboss repository换成"central"会怎么样?

<project>
	<repositories>
		<repository>
			<id>central</id>
		    <name>central</name>
			<url>https://repository.jboss.org/nexus/content/repositories/</url>
		    ...
		</repository>
		
		<repository>
			<id>google</id>
		    <name>google</name>
			<url>http://google-maven-repository.googlecode.com/svn/repository/</url>
		    ...
		</repository>		
	</repositories>     
...
</project>

答:测试表明,Maven会先去定义在最前面的repository即"central"里去找; 如果找不到,再去"google";如果还找不到,就说找不到了。也就是说,这里的"central"配置覆盖了maven的默认设置。

不建议把可以做在webapp里面的基础架构做到webapp外面

有很多基础服务,本来可以做在webapp里面的,但有人却选择把它做在webapp外面。

比如jboss提供的log4j服务,就是一个很讨厌的东西,很容易跟你应用里面的log4j冲突。

还有些服务,比如连接池服务,被强行做成了jndi,由容器来打理,这也很讨厌。

在我看来,把可以放里面的东西丢到外面有这样几个缺点:

 

  1. 本可以由程序员完全控制的基础设施,现在要由运维人员来分担了。jndi就是一个例子。

  2. 本可以由scm工具控制的东西,现在要经常手动来管理,这在版本管理方面往往产生问题。比如那些由jca写的、丢在jboss下面的东西,没办法用maven+svn直接管理了

  3. 内外冗余造成的冲突问题。如果你的应用里使用了log4j,就可能跟jboss自带的log4j产生版本冲突和class loading冲突

  4. 开发环境和其它环境的不一致问题。比如你开发用Tomcat,Tomcat不提供JNDI,所以你开发时不使用jndi那一套; 但正式环境用的又是jboss + jndi。结果就是你的代码或配置要支持两种东西,开发时不搞jndi,发布时要搞jndi

《Maven实战》笔记 2.4 - Optional依赖

Optional依赖:

  假设App依赖了A, A“可选”地依赖了B,那App在打包时,会不会纳入B?

  答案:不会。如果你的App里需要用到A中跟B相关的功能,那就需要把B用作App的直接依赖。

 可选依赖不是什么好东西,它搞得你把传递依赖升级为直接依赖,很容易令人困惑,你的同事会问:为什么App要直接依赖B?

  如果A对B有可选依赖,则应该把A拆成两个项目,其中A1依赖B,A2不依赖B,App再按需选择