最近写了太多的类似“浅尝XX”、“了解XX”、“XX入门”之类的文章,说句真心的我自己都想吐了,但是也没办法,我一个牛逼哄哄的Android工程师被当做一个纯后端使用,一堆新的概念和知识等着去学习,白天看知识点看的脑子都不灵光了,只能晚上再回忆一遍,写下来强记一下。
Maven 是现在后端常用的包管理和编译系统,本篇会系统性的介绍Maven相关的知识。本文的知识节选自:
Maven工程
在我们使用maven作为包管理系统的时候,其实也默认了使用maven风格的工程结构,这样的工程结构和Eclipse默认的工程结构区别还是挺大的,典型的maven风格:
my-app
|-- pom.xml
`-- src
|-- main
| `-- java
| `-- com
| `-- mycompany
| `-- app
| `-- App.java
`-- test
`-- java
`-- com
`-- mycompany
`-- app
`-- AppTest.java
工程根目录为 my-app
在工程目录下面会有一个 pom.xml
文件用来描述工程的属性和依赖等等。工程按 src/main/java/
作为源码路径,src/test/java/
为测试项目路径,如果还有一些资源文件需要打在jar包中,路径默认为 src/main/resources/META-INF/
。
可以手动建立这样的目录,也可以使用maven的命令自动生成:
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
这条命令需要传入3个命令行参数:
-
-DgroupId={project-packaging}
需要传入工程的包名 -
-DartifactId={project-name}
需要传入工程名 -
-DarchetypeArtifactId=maven-archetype-quickstart
创建工程时参照的模板,如果不指定模板的话,会给出一个很长的模板列表供选择
注:’-DinteractiveMode=false’ 的意思是禁用交互式模式
此时查看一下生成的模板工程中的pom.xml
文件:
<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.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Maven Quick Start Archetype</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
这个最简的POM文件很有说明性,可以分成三部分:
- “groupId/artifactId/version” 是一部分,它描述了一个工程的完整面貌
- “packaging” 描述了打包方式,即执行
mvn package
的时候如何打包 - “dependency” 描述了依赖关系,这里个工程依赖于junit测试框架(通过“groupId/artifactId/version”来描述,这样maven就可以在仓库中找到这个框架 )
注:依赖里面有个 ‘scope’ 配置,它描述了这个依赖的覆盖范围,此处为仅在测试时候使用,scope还有其它的既定的选择,它是一个枚举类型。
常用的几个maven命令:
-
mvn package
打包 -
mvn deploy
把包部署到服务器(当然要先配置好服务器地址) -
mvn clean
清空缓存和临时文件 -
mvn install
把包安装到本地的maven仓储 -
mvn compile
编译源码 -
mvn test
执行测试
配置插件
在上面的工程中,我们执行 mvn package
的时候,会触发 <packaging>jar</packaging>
对源码进行编译打包(输出为一个jar包),jar
是maven内置的一种打包插件,如果我们希望打的包是其它格式的(比如war包),那又怎么办到呢?这便是插件的用武之地了!
比如用插件来打一个war包:
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<packagingExcludes>public/**,view/**</packagingExcludes>
<webResources>
<resource>
<directory>src/main/webapp/public</directory>
<filtering>false</filtering>
</resource>
</webResources>
</configuration>
</plugin>
</plugins>
</build>
...
插件的添加格式大概如上面所示,添加新的插件的时候按照上面的格式即可,如何去获得自己需要的插件呢?这有两种途径,一种自己写一个,另外是在Maven的Plugins List里面找到自己需要的即可(因为大部分的maven任务都是雷同的,所以这里准备的插件可以满足绝大多数的需求)。
如果我们希望改变内置过程的一些编译条件,也可以用插件的方式来完成:
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
...
这样设置,让我们的源码编译条件指定为Java1.5。
依赖
在最开的示例中,已经见到了依赖的pom格式,
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
</dependencies>
大体上依赖可以分成3种:
- maven仓储中的包依赖
- 本地包(非本地仓储)依赖
- 工程依赖
第一种是大家司空见惯的依赖方式,比如上面对junit的依赖便是,这种方式会从maven的中央仓储下载jar包到本地仓储,只要按照 “groupId/artifactId/version” 的方式填写依赖便没有问题。
第二种情况一般出现在你自己有一个jar包,但是这个jar不在maven的中央仓库库里面,如果需要添加这个依赖的话,可以在工程目录下建立一个libs
目录,把用到的jar包手动拷贝到这个目录下,然后在依赖里面配置依赖为本地路径:
<dependency>
<groupId>com.alipay.mycar.demo</groupId>
<artifactId>interface</artifactId>
<version>0.0.1</version>
<type>jar</type>
<scope>system</scope>
<systemPath>${project.basedir}/libs/interface-0.0.1.jar</systemPath>
</dependency>
这时候maven是从本地路径加载的jar包,这时候 “com.alipay.mycar.demo/artifactId/version” 都可以随便写的,并且一定要注意“<scope>system</scope>”是必须的。如果使用 mvn compile
编译源码,经常会发现这样的警告:
[WARNING] Some problems were encountered while building the effective model for com.mycompany.app:my-app:jar:1.0-SNAPSHOT
[WARNING] 'dependencies.dependency.systemPath' for com.alipay.mycar.demo:interface:jar should not point at files within the project directory, ${project.basedir}/libs/interface-0.0.1.jar will be unresolvable by dependent projects @ line 17, column 21
官方虽然提供了这种方式来依赖本地jar包,但是却又十分的不推荐,官方给出的做法是用mvn install
命令把jar安装到本地仓储:
mvn install:install-file -Dfile=non-maven-proj.jar -DgroupId=some.group -DartifactId=non-maven-proj -Dversion=1 -Dpackaging=jar
其实还有一种做法,可以参考这里的文档.
第三种情况工程依赖是另一个比较重要的问题,它往往出现在多工程配置的情况,下面小节会介绍这种情况。
多工程配置
Maven的多工程配置约定是这样的:
+- pom.xml
+- my-app
| +- pom.xml
| +- src
| +- main
| +- java
+- my-webapp
| +- pom.xml
| +- src
| +- main
| +- webapp
最外层是工程的根目录,根目录下面配置一个pom.xml
文件,每个子工程都是独立的文件夹(这里的子工程分别是 my-app
和 my-webapp
),每个子工程的根目录下面还需要再配置各自的 pom.xml
文件。
父工程的POM文件:
// 父目录Pom.xml配置:
<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.mycompany.app</groupId>
<artifactId>app</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
// 在此配置了子工程的目录
<modules>
<module>my-app</module>
<module>my-webapp</module>
</modules>
</project>
子工程的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">
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>app</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
...
特殊的地方在于父工程中需要声明子工程的存在,同样子工程中需要声明自己的父工程是谁。上一节中曾经遗留了一个问题:工程间的依赖如何配置?
假设我们的 my-webapp
依赖于 my-app
,那么可以在 my-webapp
的POM文件中做如下的依赖配置:
...
<dependencies>
<dependency>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
...
</dependencies>
注:好像并没有特别意外的地方…
更多
关于Maven的配置基本都集中在这几份文档里面了: