jar 包的术语背景:
normal jar: 普通的 jar, 用于项目依赖引入, 不能通过 java -jar xx.jar 执行, 一般不包含其它依赖的 jar 包.
fat jar: 也叫做 uber jar, 是一种可执行的 jar(executable jar), 既包含自己代码中的 class , 也包含第三方依赖的 jar.
不可执行, 但包含第三方依赖的 jar 包, 避免生成的 jar 与第三方引入后出现依赖版本冲突.
1. 第一类需求: 生成单个 fat jar
使用 springboot 提供的 maven 打包插件 spring-boot-maven-plugin 即可, 方便快捷, pom 文件的配置如下:
- <!-- 测试本地 jar 包引入和打包 -->
- <!-- 项目管理的角度, 尽量不使用本地 jar 包, 搭建 maven 私服可以统一更新管理自研 jar 包 -->
- <dependency>
- <groupId>cn.henry.test</groupId>
- <artifactId>local_test</artifactId>
- <version>1.0.0</version>
- <scope>system</scope>
- <systemPath>${basedir}/src/main/local_lib/local_test.jar</systemPath>
- </dependency>
- <build>
- <plugins>
- <!-- 常规打包, flat jar, 打出来的 jar 很大, 不易于修改部分文件后增量发布 -->
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <!-- 作用: 项目打成 jar 的同时将本地 jar 包也引入进去 -->
- <configuration>
- <includeSystemScope>true</includeSystemScope>
- </configuration>
- </plugin>
- </plugins>
- </build>
2. 第二类需求: 启动项和依赖包分离的 fat jar
项目文件和依赖的 jar 包分离, 因为引用的 jar 变动较少, 项目发布时只需替换项目 jar 包或 class 即可, 使用常规 maven 打包插件, maven-jar-plugin, maven-dependency-plugin, 输出为可执行的 jar 和 lib 包, pom 文件的配置如下:
- <!-- 测试本地 jar 包引入和打包 -->
- <!-- 项目管理的角度, 尽量不使用本地 jar 包, 搭建 maven 私服可以统一更新管理自研 jar 包 -->
- <dependency>
- <groupId>cn.henry.test</groupId>
- <artifactId>local_test</artifactId>
- <version>1.0.0</version>
- <scope>system</scope>
- <systemPath>${basedir}/src/main/local_lib/local_test.jar</systemPath>
- </dependency>
- <build>
- <plugins>
- <!-- 配置文件, 依赖 jar 和可执行 jar 分离的包, 便于文件替换增量发布 -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- <!-- MANIFEST.MF 中 Class-Path 加入前缀 -->
- <classpathPrefix}41${/outputDirectory>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
3. 第三类需求: 提供给第三方使用的, 包含所有依赖的普通 jar
解决项目 jar 中依赖与引用方 jar 包版本冲突的问题, 提高 jar 包的易用性和独立性, 缺点是打出来的包较大, jar 包内置依赖不透明. 使用 maven 打包插件 maven-shade-plugin,pom 文件的配置如下:
在 cmd 中切换到 local_test.jar 包所在的目录, 执行
mvn install:install-file "-DgroupId=cn.henry.frame" "-DartifactId=local_test" "-Dversion=1.0.0" "-Dpackaging=jar" "-Dfile=local_test.jar"
其中:
-DgroupId 为 maven 依赖的 groupId
-DartifactId 为 maven 依赖的 artifactId
-Dversion 为 maven 依赖的 version
-Dfile 为 local_test.jar 包的文件名
引入安装后的 local_test.jar 包, maven 依赖如下:
- <!-- 项目管理的角度, 尽量不使用本地 jar 包, 搭建 maven 私服可以统一更新管理自研 jar 包 -->
- <dependency>
- <groupId>cn.henry.frame</groupId>
- <artifactId>local_test</artifactId>
- <version>1.0.0</version>
- </dependency>
- <build>
- <plugins>
- <!-- 提供给第三方使用的, 包含所有依赖的普通 jar -->
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-shade-plugin</artifactId>
- <executions>
- <execution>
- <phase>package</phase>
- <goals>
- <goal>shade</goal>
- </goals>
- <configuration>
- <!-- 加入启动类 -->
- <!--<transformers>
- <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
- <mainClass>xxx.xxx</mainClass>
- </transformer>
- </transformers>-->
- <createDependencyReducedPom>false</createDependencyReducedPom>
- <filters>
- <filter>
- <artifact>*:*</artifact>
- <excludes>
- <exclude>META-INF/*.SF</exclude>
- <exclude>META-INF/*.DSA</exclude>
- <exclude>META-INF/*.RSA</exclude>
- </excludes>
- </filter>
- </filters>
- </configuration>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
4. 第四类需求: 提供给第三方使用的, 仅包含项目代码的普通 jar
通用模式, 如果项目中有使用到第三方依赖, 需要提供说明, 否则会直接报 class not found exception. 使用 maven 打包插件 maven-jar-plugin,pom 文件的配置如下:
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <manifest>
- <addClasspath>true</addClasspath>
- </manifest>
- </archive>
- </configuration>
- </plugin>
注意打包插件的版本选择, 尽量使用高版本, 官方可能修复了已存在的问题, 按项目的需求选取打包方式.
maven 的打包插件官网: http://maven.apache.org/plugins https://maven.apache.org/plugins
插件打包的原理: 读取 xml 配置, 组装成规范的 jar 文件
jar 规范可以阅读 oracle 的官方文档:
重点关注的部分: JAR 文件格式中 META-INF 目录下的 MANIFEST.MF 文件, 用于定义扩展和包相关的数据. 主属性: Manifest-Version(MF 文件版本号), Main-Class(包含 main 方法的类), Class-Path(执行这个 jar 包时的 ClassPath, 第三方依赖)
- Manifest-Version: 1.0
- Main-Class: test.Main
- Class-Path: ./ ./lib/commons-collections-3.2.jar ./lib/commons-lang-2.3.jar ./lib/commons-logging-1.1.jar
打包的一般做法是扫描项目所依赖的包, 按照规范拼接 Class-Path 的 value 值, 写入 MF 文件. 但这种做法不够灵活, 框架通常会从 MF 文件获取自定义信息, 使用 classloader 动态加载依赖的 jar 包, 并控制文件的合并, 过滤等规则.
来源: http://www.bubuko.com/infodetail-3367413.html