Maven 入门

9.22'22

介绍

Maven 是 Java 项目的管理构建工具。默认配置文件是 pom.xml,使用声明式的语法。

使用

安装

Spring 项目可以使用项目内的 Maven wrapper mvnw

手动创建项目

在项目下

mkdir -p src/main/java/hello

hello目录下添加类文件

HelloWorld.java

package hello;

public class HelloWorld {
    public static void main(String[] args) {
        Greeter greeter = new Greeter();
        System.out.println(greeter.sayHello());
    }
}

Greeter

package hello;

public class Greeter {
    public String sayHello() {
        return "Hello world";
    }
}

配置

Maven 项目使用 XML 文件pom.xml,定义项目信息和构建的配置。包含项目名字、版本、依赖等。

一个最简单的pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-maven</artifactId>
    <packaging>jar</packaging>
    <version>0.1.0</version>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-shade-plugin</artifactId>
                <version>2.1</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>shade</goal>
                        </goals>
                        <configuration>
                            <transformers>
                                <transformer
                                    implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                    <mainClass>hello.HelloWorld</mainClass>
                                </transformer>
                            </transformers>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
  • <modelVersion>. POM model version (always 4.0.0).
  • <groupId>. Group or organization that the project belongs to.
  • <artifactId>. Name to be given to the project's library artifact(for example, the name of its JAR or WAR file).
  • <version>.
  • <packaging>. How the project should be packaged. Defaults to "jar" for JAR file packaging. Use "war" for WAR file packaging.

Build

For target/classes

mvn compile

For target/<artifactId>-<version>.jar

# Compile, run any tests, package the code up in a JAR file.
mvn package

To execute the JAR file

java -jar target/gs-maven-0.1.0.jar

Maven 把所有用到的依赖放在本地依赖仓库中,通常为~/.m2/repository.如果需要把当前项目也添加到该仓库、给其它项目使用,可以运行

# Package, then copy it into local dependency repository.
mvn install

管理依赖

大部分应用会用到外部的库来实现通用或复杂的功能。

例如,可以使用Joda库来处理日期和时间。

HelloWorld.java

package hello;

import org.joda.time.LocalTime;

public class HelloWorld {
    public static void main(String[] args) {
        LocalTime currentTime = new LocalTime();
        System.out.println("The current local time is: " + currentTime);
        Greeter greeter = new Greeter();
        System.out.println(greeter.sayHello());
    }
}

直接运行mvn package会报错,找不到依赖包。需要在pom.xml中配置,<project>元素下添加

<dependencies>
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.9.2</version>
    </dependency>
</dependencies>

声明了单个依赖的基本信息。

再运行mvn package,maven 会先从远程仓库,下载对应版本依赖到本地依赖仓库中。

远程仓库默认在 https://mvnrepository.com/ 搜索查看, 下载地址在~/.m2/settings.xml中修改。参考 Maven – Introduction to Repositories

  • 依赖配置:~/.m2/settings.xml

    远程仓库地址、用户名、密码等

  • 依赖安装地址:~/.m2/repository

配置文件

Maven 配置分为三个层次

  • Project - pom.xml

  • Installation - Added once for a Maven installation

  • User - ~/.m2/settings.xml

命令快速生成新项目

创建项目

初始化项目,使用archetype:generate和相关参数,创建了目录 my-app

mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

项目结构

cd my-app

标准项目结构

my-app
|----pom.xml
|----src
| |----main
| | |----java
| | | |----com
| | | | |----mycompany
| | | | | |----app
| | | | | | |----App.java
| |----test
| | |----java
| | | |----com
| | | | |----mycompany
| | | | | |----app
| | | | | | |----AppTest.java

src/main/java包含了项目的源代码, pom.xml(Project Object Model,POM)包含了项目的基本配置信息。

pom.xml example:

<?xml version="1.0" encoding="UTF-8"?>

<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>

  <name>my-app</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>
</project>

编译打包

mvn package

package is a phase, a step in the build lifecycle.

A build lifecycle is made up of phases, a build phase is made of plugin goals.

运行

java -cp target/my-app-1.0-SNAPSHOT.jar com.mycompany.app.App

成功后会输出:

Hello World!

生成项目信息的网页

mvn site

生成的网页在文件夹 target/site

其它

如果编译成功后运行,提示 错误: 找不到或无法加载主类,可以尝试

java -jar target/my-app-1.0-SNAPSHOT.jar

常见问题

Maven dependency resolution (conflicted)

https://stackoverflow.com/questions/7175398/maven-dependency-resolution-conflicted

Maven can handle both situations without any conflict. Conflicts will exist when two versions of a transitive dependency are required. The ClassNotFoundException you describe results from the app (or a dependency) attempting to use a class not available in the version of the conflicted dependency that actually gets used. There are multiple ways to fix the problem.

  • Update the versions of the libraries you are using that depend on the conflicted dependency, so that they all depend on the same version version of that dependency
  • Declare the conflicted dependency as a direct dependency of your project with the version you want to be included (in the example, the one with the missing class included in it)
  • Specify which version of the conflicted dependency that transitive dependencies should use, via the <dependencyManagement> section of the POM
  • Explicitly exclude the unwanted versions of the conflicted dependency from being included with the dependencies that rely on them using an <exclusion>

  • mvn depencency:analyze
  • mvn depencency:tree
📖