使用Maven将Java代码打成JAR包

学习使用Maven将下面的Java测试代码打成JAR包

测试代码:

public class Main {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

创建项目

在这里插入图片描述

目录结构

创建成功之后目录结构是如下图:

在这里插入图片描述

标准的Maven项目目录结构:

your-project/
├── pom.xml
└── src/
    └── main/
        └── java/
            └── Main.java

Maven常用命令

# 清理项目
mvn clean

# 编译项目
mvn compile

# 打包项目
mvn package

# 安装到本地仓库
mvn install

# 跳过测试打包
mvn package -DskipTests

解决报错

开始打包

# 清理并打包
mvn clean package

# 或者只执行打包
mvn package

执行完成之后没有报错,时间挺长的。然后执行:

java -jar target/prjct01-1.0-SNAPSHOT.jar

报错:no main manifest attribute, in prjct01-1.0-SNAPSHOT.jar

这个错误是因为JAR包中没有指定主类。

查看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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>prjct01</artifactId>
    <version>1.0-SNAPSHOT</version>

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

</project>

问题在于没有配置maven-jar-plugin插件来指定主类。您需要在<project>标签内添加<build>配置。

在您的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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>prjct01</artifactId>
    <version>1.0-SNAPSHOT</version>

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

    <build>
        <plugins>
            <!-- 编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
            
            <!-- JAR打包插件 - 关键配置 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <!-- 指定主类 -->
                            <mainClass>Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

重新打包之后运行,继续报错:

java -jar target/prjct01-1.0-SNAPSHOT.jar 
Error: Could not find or load main class Main
Caused by: java.lang.ClassNotFoundException: Main

使用命令进行诊断:

jar tf target/prjct01-1.0-SNAPSHOT.jar

pokes@userver:~/prjct01$ jar tf target/prjct01-1.0-SNAPSHOT.jar
META-INF/MANIFEST.MF
META-INF/
org/
org/example/
META-INF/maven/
META-INF/maven/org.example/
META-INF/maven/org.example/prjct01/
org/example/Main.class
META-INF/maven/org.example/prjct01/pom.xml
META-INF/maven/org.example/prjct01/pom.properties

看到问题了!您的Main类在org.example包中,但pom.xml中配置的主类是Main,应该是org.example.Main

解决方案:

<?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>org.example</groupId>
    <artifactId>prjct01</artifactId>
    <version>1.0-SNAPSHOT</version>

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

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.2.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <!-- 修改这里:使用完整包名 -->
                            <mainClass>org.example.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

重新打包和运行

# 重新打包
mvn clean package

# 运行JAR包
java -jar target/prjct01-1.0-SNAPSHOT.jar

在这里插入图片描述

成功了!以上的报错最终的原因是因为,我们对Maven的配置文件pom.xml文件不熟悉。

Maven的配置文件POM.xml

简单来说,Pom.xml 是 Maven 项目的核心配置文件,它相当于 Maven 项目的“大脑”和“蓝图”。

它的全称是 Project Object Model,即项目对象模型。这个文件包含了构建和管理项目所需的一切信息。

详细解释

1. 核心作用

POM.xml 文件定义了项目的基本信息、如何构建项目、项目的依赖关系以及如何发布项目等。没有它,Maven 就无法工作。

2. 关键组成部分

一个典型的 pom.xml 文件包含以下主要部分:

  • 项目坐标: 项目的唯一标识符,类似于地理坐标。

    • groupId: 公司或组织的唯一标识,通常使用反向域名(如 com.google)。
    • artifactId: 项目在该组织下的唯一名称。
    • version: 项目的版本号(如 1.0-SNAPSHOT)。
    • packaging: 项目的打包方式(如 jar, war, pom)。默认为 jar

    这三个元素(groupId, artifactId, version)合在一起,构成了一个依赖项在全球 Maven 仓库中的唯一坐标。

  • 依赖管理: 声明项目所依赖的外部库(JAR 包)。

    • <dependencies> 部分中,通过 坐标 来声明每一个依赖。
    • Maven 会自动从中央仓库或你配置的仓库下载这些依赖,并管理它们之间的传递性依赖。
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>5.3.0</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    
  • 构建配置: 定义如何编译、测试和打包项目。

    • <build> 部分中,你可以配置源代码目录、资源文件目录、使用的插件(如编译器插件、打包插件)等。

    xml

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    
  • 父 POM 和继承:

    • 可以通过 <parent> 元素指定一个父 POM。子模块会继承父 POM 中定义的依赖、插件和配置,这极大地促进了多模块项目的一致性和可维护性。
    • Spring Boot 等框架就大量使用了这个特性。
  • 属性:

    • <properties> 部分可以定义一些常量,如项目编码、Java 版本等,方便在文件的其他地方引用,保持统一和易于修改。

    xml

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <java.version>11</java.version>
    </properties>
    
  • 仓库配置:

    • 可以配置除了中央仓库之外的私有仓库(如公司内部的 Nexus 或 JFrog Artifactory),用于存放公司内部的构件或代理中央仓库。

一个简单的 pom.xml 示例

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 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    
    <!-- 模型版本,对于 Maven 2 和 3 来说,基本都是 4.0.0 -->
    <modelVersion>4.0.0</modelVersion>

    <!-- 项目坐标 -->
    <groupId>com.example</groupId>
    <artifactId>my-first-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <!-- 项目属性 -->
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <!-- 项目依赖 -->
    <dependencies>
        <!-- 单元测试依赖 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!-- 构建配置 -->
    <build>
        <plugins>
            <!-- 编译器插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
            </plugin>
        </plugins>
    </build>
</project>

带注释版本:

<?xml version="1.0" encoding="UTF-8"?>
<!-- XML声明,指定文档版本和字符编码 -->
<project xmlns="http://maven.apache.org/POM/4.0.0"
         <!-- 定义XML命名空间,指定这是Maven POM文档 -->
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         <!-- 引入XML Schema实例命名空间 -->
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
         <!-- 指定XML Schema的位置,用于验证文档结构 -->
    
    <!-- 模型版本,对于 Maven 2 和 3 来说,基本都是 4.0.0 -->
    <modelVersion>4.0.0</modelVersion>
    <!-- POM模型版本,指定使用的POM格式版本 -->

    <!-- ========== 项目坐标 ========== -->
    <groupId>com.example</groupId>
    <!-- 组织或公司的唯一标识,通常使用反向域名 -->
    <artifactId>my-first-app</artifactId>
    <!-- 项目名称,在组织内唯一 -->
    <version>1.0-SNAPSHOT</version>
    <!-- 项目版本号,SNAPSHOT表示开发中的版本 -->
    <packaging>jar</packaging>
    <!-- 项目打包方式,jar表示打包成JAR文件 -->

    <!-- ========== 项目属性 ========== -->
    <properties>
        <!-- 定义项目属性,类似于变量 -->
        <maven.compiler.source>11</maven.compiler.source>
        <!-- 指定源代码使用的Java版本 -->
        <maven.compiler.target>11</maven.compiler.target>
        <!-- 指定编译生成的字节码目标版本 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <!-- 指定项目源码的字符编码 -->
    </properties>

    <!-- ========== 项目依赖 ========== -->
    <dependencies>
        <!-- 依赖列表,定义项目所需的所有第三方库 -->
        
        <!-- 单元测试依赖 -->
        <dependency>
            <!-- 定义一个依赖项 -->
            <groupId>junit</groupId>
            <!-- 依赖的组织ID -->
            <artifactId>junit</artifactId>
            <!-- 依赖的项目ID -->
            <version>4.13.2</version>
            <!-- 依赖的版本号 -->
            <scope>test</scope>
            <!-- 依赖的作用范围,test表示仅在测试时可用 -->
        </dependency>
    </dependencies>

    <!-- ========== 构建配置 ========== -->
    <build>
        <!-- 构建配置部分 -->
        <plugins>
            <!-- 插件列表,定义构建过程中使用的Maven插件 -->
            
            <!-- 编译器插件 -->
            <plugin>
                <!-- 定义一个Maven插件 -->
                <groupId>org.apache.maven.plugins</groupId>
                <!-- 插件所属的组织 -->
                <artifactId>maven-compiler-plugin</artifactId>
                <!-- 插件的名称 -->
                <version>3.8.1</version>
                <!-- 插件的版本号 -->
            </plugin>
        </plugins>
    </build>
</project>
<!-- POM配置文件的结束标签 -->

关键点总结:

  1. 项目坐标groupIdartifactIdversion 这三个元素唯一标识了一个项目,被称为Maven坐标。
  2. 属性配置:在 <properties> 中定义的属性可以在整个POM文件中引用,便于统一管理。
  3. 依赖管理<dependencies> 部分声明项目所需的外部库,Maven会自动下载和管理这些依赖。
  4. 构建插件<build> 部分配置构建过程中使用的插件,如编译器插件、打包插件等。
  5. 作用域<scope>test</scope> 表示这个依赖只在运行测试时使用,不会打包到最终的制品中。

可以将 pom.xml 理解为:

  1. 项目的身份证:定义了项目是谁。
  2. 项目的购物清单:列出了项目需要哪些第三方库。
  3. 项目的构建说明书:详细说明了如何编译、测试和打包项目。
  4. 项目的家族树:通过继承机制,管理多模块项目。

正是因为有了这个标准化的配置文件,Maven 才能实现 “约定优于配置” 的原则,让开发者从繁琐的构建配置中解放出来,并且保证了项目构建过程的一致性和可重复性。

更多推荐