Maven的安装和基础知识的学习

Java后台的项目管理肯定是要使用Maven的.

2016-03-06 | 阅读

Maven安装和配置

去官网下载Maven,解压后即安装完成,跟Tomcat类似.然后设置环境参数:

export M2_HOME=/Users/luoxianming/developer/maven
export PATH=$PATH:~M2_HOME/bin

默认mac系统安装了jdk,但是没有设置好环境变量,所以还需要设置:

 export JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_51.jdk/Contents/Home

然后输入mvn -v验证是否正确安装.

然后配置镜像,在安装目录下编辑conf/settings.xml文件.

中插入以下代码来配置镜像地址.

<mirror>
  <id>nexus-osc</id>
  <mirrorOf>*</mirrorOf>
  <name>Nexus osc</name>
  <url>http://maven.oschina.net/content/groups/public/</url>
</mirror>

但是执行Maven命令时,还需要安装一些插件包,这些插件包的下载地址也要指向oschina.net的Maven地址.在<profiles>中插入:

<profile>
  <id>jdk-1.4</id>
  <activation>
  <jdk>1.4</jdk>
  </activation>
  <repositories>
    <repository>
      <id>nexus</id>
      <name>local private nexus</name>
      <url>http://maven.oschina.net/content/groups/public/</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <id>nexus</id>
      <name>local private nexus</name>
      <url>http://maven.oschina.net/content/groups/public/</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
    </pluginRepository>
  </pluginRepositories>
</profile>

Maven

Maven是一个项目管理和构建自动化工具.所有的项目有以下的结构.

  • ${basedir} : 存放pom.xml和所有的子目录
  • ${basedir}/src/main/java : 项目的java源代码
  • ${basedir}/src/main/resources : 项目的资源,比如property文件
  • ${basedir}/src/test/java : 项目的测试类,比如说JUnit代码.
  • ${basedir}/src/test/resources : 测试用的资源

一个maven项目在默认情况下会产生JAR文件,另外,编译后的classes,会放在${basedir}/target/classes下面,JAR文件会放在{basedir}/target下面.

安装和配置后,来创建第一个Maven项目.这里通过命令来创建应用:

mvn archetype:generate -DgroupId=com.lxm.helloworld -DartifactId=helloworld -Dpackage=com.lxm.helloworld -Dversion=1.0-SNAPSHOT

archetype:generate目标会列出一系列archetype项目的模型供选择,Maven提供了很多种Archetype,包括简单的Swing到复杂的Web应用,这里选择默认的maven-archetype-quickstart,编号106.maven为我们创建的目录结构如下:

文件目录

pom.xml文件用于描述项目,配置插件和管理依赖关系.Maven已经为我们创建了一个App.java的文件,其中写着Hello world 的代码.我们要构建和运行这个程序.进入pom.xml所在文件目录.运行命令mvn package进行打包.运行maven下载的程序会放在本地库中,路径默认为~/.m2/repository/下.构建完成,会新建一个target文件夹,打包的jar包放在该文件夹下,编译后的class文件放在target/classes下,测试类的class文件放在target/test-classes目录下.运行jar文件,验证成功.

POM (Project Object Model)

一个项目的所有的配置都放在POM文件中,定义项目的类型,名称,管理依赖关系,定制插件等等.例如你可以配置compiler插件来使用java1.5编译.上面直接创建的maven项目的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">
     <modelVersion>4.0.0</modelVersion> 

     <groupId>com.lxm.helloworld</groupId> 
     <artifactId>helloworld</artifactId> 
     <version>1.0-SNAPSHOT</version> 
     <packaging>jar</packaging> 

     <name>helloworld</name> 
     <url>http://maven.apache.org</url> 

     <properties> 
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     </properties> 

     <dependencies>
       <dependency> 
         <groupId>junit</groupId> 
         <artifactId>junit</artifactId> 
         <version>3.8.1</version> 
         <scope>test</scope> 
       </dependency> 
     </dependencies> 
    </project>   

在POM中,groupId,artifactId,packaging,version叫做maven坐标,唯一的确定一个项目.使用Maven坐标,来指定我们项目所依赖的其他项目,插件或父项目.一般maven坐标写成如下格式:

groupId:artifactId:packaging:version

则创建的helloworld项目就为:

com.lxm.helloworld: helloworld: jar: 1.0-SNAPSHOT

大型项目会分为几个子项目,每个子项目都有自己的POM文件,然后有一个公共的父项目,只要构建父项目就会构建所有的子项目. 子项目的POM继承父项目的POM.另外所有的POM都继承了一个Super-POM.Super-POM会设置一些默认值,比如默认的目录结构,默认的插件等等.当前文件中看的内容并不是全部的POM文件,如果想要看到完整的POM文件,运行以下命令:

mvn help:effective-pom

Maven插件

之前使用archetype:generate来生成一个项目,那么这里的archetype是一个插件的名字,generate是目标goal的名字,这个命令是告诉maven执行archetype插件的generate目标.插件通常会写成plugin:goalId.

一个目标是一个工作单元,而插件是一个或多个目标的结合.比如Jar插件,Compiler插件和Surefire插件等.Jar插件包含建立Jar的目标,Compiler插件包含编译源代码和单元测试代码的目标,Surefire插件用于运行单元测试.

mvn本身不会做太多的事情,它不知道怎么编译或者怎么样打包,而是把构建的任务交给插件去做.插件定义了常见的构建逻辑,能够被重复利用,这样一旦插件有更新,全部的maven用户都能得到相应的更新.

Maven生命周期

之前使用的命令 mvn package,这里的package是一个maven的生命周期阶段.生命周期表示项目构建过程中的一些有序阶段,每个阶段都是构建的一个步骤.

插件目标可以绑定到生命周期阶段上,一个生命周期阶段可以绑定多个插件,当maven构建过程中,逐步通过各个阶段时,会执行该阶段上的插件目标.

maven支持不同的生命周期,默认的Maven生命周期如下:

  • process-resources 阶段 : resources:resources
  • compile阶段 : compiler:compile
  • process-classes阶段: 默认无目标
  • process-test-resources阶段: resources:testResources
  • test-compile阶段: compiler:testCompile
  • test阶段: surefire:test
  • prepare-package阶段: 默认无目标
  • package阶段 : jar:jar

Maven依赖管理

Maven坐标可以确定一个项目,而我们也可以用它来解决依赖关系.在POM中,依赖关系是在dependencies部分中定义的,如在上例中,我们可以定义对于junit的依赖:

<dependencies> 
    <dependency> 
      <groupId>junit</groupId> 
      <artifactId>junit</artifactId> 
      <version>3.8.1</version> 
      <scope>test</scope> 
    </dependency> 
  </dependencies> 

这个例子很简单,但是很多时候我们会遇到依赖传递,即我们依赖的jar包同时有着自己的依赖,但我们不需要将这些间接依赖的jar文件也定义在POM中,Maven为我们提供了依赖传递的特性.在本地库中,可以看到junit的文件路径下,不仅下载了jar文件,还下载了它的POM文件,这样maven就会检查junit的依赖关系,将其所需要的依赖也包括进来.

在POM的dependencies部分,scope决定了依赖关系的使用范围,其有5个值:

  • compile : 缺省值,用于所有阶段,会随项目一起发布
  • provided : 类似compile,期望JDK 容器或使用者会提供这个依赖.
  • runtime : 只在运行时使用,如JDBC驱动,使用运行和测试阶段.
  • test : 只在测试阶段使用
  • system : 类似provided,需要显式提供一个本地文件系统的JAR文件.这是基于本地对象的编译.不推荐使用.

Maven库

当第一次运行maven命令的时候,需要网络,以下载一些文件,内容由默认的远程库中下载核心插件和jar文件.

如果是自己开发的项目,可以在公司内网设置定制库,或者手动下载或者安装jar文件到本地库中.本地库在Linux上默认路径是~/.m2/repository.

运行以下命令可以将项目安装到本地库中:

mvn install

一旦有项目被安装到本地库,别的项目就可以通过maven坐标和这个项目建立依赖关系.

Maven项目的编码集问题

使用Maven管理项目后,遇到最麻烦的问题就是编码集的问题.Maven编译时和其他所有过程所用到的默认编码集是系统的默认编码集,而在IDEA中设置了整个项目使用的编码集与其不同时,会出现两种错误.一种是maven编码gbk的不可映射字符,一种是最终输出中文全部为问号?.这些问题的解决都要通过设置maven项目的编码集.简单的设置如下:

<!-- 文件拷贝时的编码 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

中文乱码问题,有多个问题:

  • surefire插件,使用jvm的编码集选择问题,设置为jvm option即可 ,如下 :

      <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <version>2.19.1</version>
             <configuration>
               <argLine>-Dfile.encoding=UTF-8</argLine>
             </configuration>
        </plugin>
    
  • 然后部署到tomcat上并运行,也会遇到同样的问题,依旧是jvm使用了系统默认的编码集,所以还是要加上jvm option.-Dfile.encoding=UTF-8
  • 还有就是Maven编译构建时使用的编码集,也是系统默认编码集,也要进行设置。

在详细研究一下编码集问题

检测当前jvm使用编码集:

public static void main(String[] args) {  
        System.out.println("Default Charset=" + Charset.defaultCharset());  
        System.out.println("file.encoding=" + System.getProperty("file.encoding"));  
        System.out.println("Default Charset=" + Charset.defaultCharset());  
        System.out.println("Default Charset in Use=" + getDefaultCharSet());  
    }  
  
    private static String getDefaultCharSet() {  
        OutputStreamWriter writer = new OutputStreamWriter(new ByteArrayOutputStream());  
        String enc = writer.getEncoding();  
        return enc;  
    } 

然后我直接运行这个main函数,输出的编码集是UTF-8,因为IDEA直接运行main函数是,调用jdk就选择了编码集,使用了-Dfile.encoding=UTF-8来设置JVM.

而我将项目部署到当前的tomcat上时,直接使用的是JVM设定的默认编码集,是US-ASCII,所以无法正常输出中文,但是从数据库中获取的UTF-8编码集的数据直接传递给jsp界面并以UTF-8显示,这个流程是不会出现乱码问题的.

解决方法的话,有两种,一种是修改系统编码集,然后jvm使用的是系统默认的,所以也会跟着修改.一种设置JVM启动参数,加上-Dfile.encoding=UTF-8.

显然后者更靠谱,具体做法是:

在系统变量中设置JAVA_TOOL_OPTIONS,添加上编码集设置-Dfile.encoding=UTF-8.这样每次启动jvm都会使用UTF-8编码集.

Maven中使用本地jar包

这里介绍3种做法:

  1. 将jar包安装到本地repository中:

     mvn install:install-file -Dfile=my-jar.jar -DgroupId=org.richard -DartifactId=my-jar -Dversion=1.0 -Dpackaging=jar
    
  2. 添加in project repository ,这样即使在新机器上,也不要运行mvn install命令了:

     <repository>
         <id>in-project</id>
         <name>In Project Repo</name>
         <url>file://${project.basedir}/lib</url>
     </repository>
    

    但jar包和路径必须遵循格式:

     /groupId/artifactId/version/artifactId-verion.jar
    
  3. 使用 systemPath

    <dependency>
        <groupId>com.jhlabs</groupId>
        <artifactId>simplecaptcha</artifactId>
        <version>1.0</version> 
        <scope>system</scope> 
        <systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/simplecaptcha-latest.jar</systemPath>  
    </dependency>