1、shade

也就是所说的fat jar所有相关的类(含依赖)会被打进一个jar包

1.1、优点

  1. shade支持修剪不必要的依赖,不像assembly需要用户自己进行修剪,shade能过通过字节码分析自动修剪掉不必要的依赖
  2. 能够通过替换包名避免依赖冲突,如果一个项目中同时依赖了某个库的两个版本,比如spark程序中,自己的代码依赖okhttp3, spark本身的代码依赖okhttp2,此时除了重写自己的代码,更改依赖外,还可以通过shade解决依赖冲突。巧用maven-shade-plugin解决依赖冲突

1.2、缺点

  1. 不能打thin jar 即使shade能够修剪依赖,最终也只能将所有类打到一个jar包中
  2. 无法打包脚本,配置文件等

1.3、一般使用

<build>
        <plugins>
            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.1.1</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <filters>
                            <filter>
                                <!-- Do not copy the signatures in the META-INF folder.
                                Otherwise, this might cause SecurityExceptions when using the JAR. -->
                                <artifact>*:*</artifact>
                                <excludes>
                                    <exclude>META-INF/*.SF</exclude>
                                    <exclude>META-INF/*.DSA</exclude>
                                    <exclude>META-INF/*.RSA</exclude>
                                </excludes>
                            </filter>
                        </filters>
                        <!--<transformers>
                            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <mainClass>demo.SocketWindowWC</mainClass>
                            </transformer>
                        </transformers>-->
                    </configuration>
                </execution>
            </executions>
        </plugin>
        </plugins>
    </build>

可以使用 relocations、filters、artifactSet(includes) 来解决jar冲突

2、assembly

2.1、优点

  1. thin jar 如果打fat jar,所有相关的类(含依赖)会被打进一个jar包,此时的问题是这个包除了比较大外,还失去了通过替换jar包更新程序的灵活性。assembly不会将依赖的jar包合并,仅仅是将它们放在一个压缩包中
  2. 打包脚本,配置文件等 assembly除了打包依赖外,还能include用户定义的目录或文件。如一般项目都会在bin目录中放启动脚本等
  3. 自定义依赖 assembly默认打包所有依赖的依赖,默认行为可能会打出很多jar包,可以手动include/exclude

2.2、缺点

手动依赖修剪assembly虽然可以通过定义include/exclude修剪依赖,但是需要用户明确自己的代码中用到了哪些,没用到哪些,否则如果该include没有include或被exclude了,那么很容易出No Class Found Exception

2.3、实例

pom.xml

<build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <configuration>
          <excludes>
            <exclude>*.yaml</exclude>
            <exclude>*.xml</exclude>
          </excludes>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <executions>
          <execution>
            <id>java-test</id>
            <goals>
              <!-- 只运行一次 -->
              <goal>single</goal>
            </goals>
            <!-- 绑定到package生命周期 -->
            <phase>package</phase>
            <configuration>
              <finalName>java-test</finalName>
              <!-- 配置描述符文件 -->
              <descriptors>
                <descriptor>src/main/assembly/java-test.xml</descriptor>
              </descriptors>
              <appendAssemblyId>false</appendAssemblyId>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

assembly/java-test.xml

<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
    <id>java-test</id>
    <formats>
        <format>tar.gz</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <baseDirectory>java-test</baseDirectory>
    <fileSets>
        <fileSet>
            <directory>${basedir}/src/main/resources</directory>
            <includes>
                <include>*.properties</include>
            </includes>
            <outputDirectory>conf</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>${basedir}/src/main/bin</directory>
            <outputDirectory>bin</outputDirectory>
            <fileMode>0755</fileMode>
            <directoryMode>0755</directoryMode>
        </fileSet>
    </fileSets>
    <dependencySets>
        <dependencySet>
            <outputDirectory>libs</outputDirectory>
        </dependencySet>
    </dependencySets>
</assembly>

bin

jvm_args_env.sh

-Xms1g
-Xmx1g
-Xmn512m

-XX:+IgnoreUnrecognizedVMOptions
-XX:+PrintGCDateStamps
-XX:+PrintGCDetails
-Xloggc:gc.log

-XX:+ExitOnOutOfMemoryError
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=dump.hprof

-Duser.timezone=${SPRING_JACKSON_TIME_ZONE}

start.sh

BIN_DIR=$(dirname $0)
JAVATEST_HOME=${JAVATEST_HOME:-$(cd $BIN_DIR/..; pwd)}


JVM_ARGS_ENV_FILE=${BIN_DIR}/jvm_args_env.sh
JVM_ARGS="-server"

if [ -f $JVM_ARGS_ENV_FILE ]; then
  while read line
  do
      if [[ "$line" == -* ]]; then
        JVM_ARGS="${JVM_ARGS} $line"
      fi
  done < $JVM_ARGS_ENV_FILE
fi

JAVA_OPTS=${JAVA_OPTS:-"${JVM_ARGS}"}

if [[ "$DOCKER" == "true" ]]; then
  JAVA_OPTS="${JAVA_OPTS} -XX:-UseContainerSupport"
fi

echo "JAVA_HOME=${JAVA_HOME}"
echo "JAVA_OPTS=${JAVA_OPTS}"

$JAVA_HOME/bin/java $JAVA_OPTS \
  -cp "$JAVATEST_HOME/conf":"$JAVATEST_HOME/libs/*" \
  com.cestc.bigdata.java.JavaTask

程序

public class PropertyUtils {
    private static Properties properties;
    
    static {
        try (InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties")) {
            properties = new Properties();
            properties.load(in);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static String getString(String key) {
        return properties.getProperty(key);
    }
}
public class JavaTask {

    public static void main(String[] args) {
        String name = PropertyUtils.getString("name");
        Integer age = Integer.parseInt(PropertyUtils.getString("age"));
        System.out.println("name : " + name + "; age :" + age);
    }
}

resources/config.properties

name=zhangsan
age=20

打包测试
mvn clean package

qiaozhanwei@qiaozhanweideMacBook-Pro target % sh bin/start.sh 
JAVA_HOME=/Users/qiaozhanwei/Downloads/InstallProgram/jdk1.8.0_401.jdk/Contents/Home
JAVA_OPTS=-server -Xms1g -Xmx1g -Xmn512m -XX:+IgnoreUnrecognizedVMOptions -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:gc.log -XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=dump.hprof
name : zhangsan; age :20

3、使用 maven-compiler-plugin 与 maven-shade-plugin 组合

maven-shade-plugin 主要用于生成 “uber JAR”(包含所有依赖的可执行 JAR 文件)并且提供重定位功能,避免类冲突

<build>
    <plugins>
        <!-- 编译插件:编译源代码 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>

        <!-- 打包插件:生成包含依赖的 uber JAR -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>3.2.4</version>
            <executions>
                <execution>
                    <phase>package</phase> <!-- 在打包阶段执行 -->
                    <goals>
                        <goal>shade</goal> <!-- 使用 shade 目标 -->
                    </goals>
                    <configuration>
                        <createDependencyReducedPom>true</createDependencyReducedPom> <!-- 生成依赖精简的 POM 文件 -->
                        <archive>
                            <manifestEntries>
                                <Main-Class>com.example.MainClass</Main-Class> <!-- 主类 -->
                            </manifestEntries>
                        </archive>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

构建过程:
1、编译阶段: 使用 maven-compiler-plugin 将 Java 源代码编译为字节码(.class 文件)。
2、打包阶段: 使用 maven-shade-plugin 将编译后的代码与所有依赖项一起打包成一个 “uber JAR” 文件,并且可以通过 createDependencyReducedPom 生成一个精简的 POM 文件以减少依赖管理问题。

生成的文件:
target/my-app-1.0-SNAPSHOT-shaded.jar(包含依赖的可执行 JAR 文件)

4、使用 maven-compiler-plugin 与 maven-assembly-plugin 组合

maven-assembly-plugin 也可以生成 “fat JAR”(包含所有依赖的可执行 JAR 文件),并且可以生成其他格式的压缩包如 ZIP、TAR 等

<build>
    <plugins>
        <!-- 编译插件:编译源代码 -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>

        <!-- 打包插件:生成包含依赖的 fat JAR -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>3.3.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>com.example.MainClass</mainClass> <!-- 主类 -->
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef> <!-- 指定打包依赖的方式 -->
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase> <!-- 在打包阶段执行 -->
                    <goals>
                        <goal>single</goal> <!-- 使用 single 目标 -->
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

构建过程
1、编译阶段: 使用 maven-compiler-plugin 将 Java 源代码编译为字节码。
2、打包阶段: 使用 maven-assembly-plugin 将编译好的代码及所有依赖项打包成一个 “fat JAR” 文件。

生成的文件
target/my-app-1.0-SNAPSHOT-jar-with-dependencies.jar(包含依赖的可执行 JAR 文件)

5、maven-jar-plugin(非必须)

如果你使用了 maven-assembly-plugin 或 maven-shade-plugin 来生成包含所有依赖项的 “fat JAR” 或 “uber JAR”,这些插件本身可能会处理 JAR 文件的创建,并且 maven-jar-plugin 可以不需要单独配置
注意 : 如果要使用 -javaagent 提供 jar,需要使用它

  • 主要功能: 用于创建标准的 JAR 文件。
  • 用途: 打包项目的编译输出(类文件和资源)到一个 .jar 文件中。你可以定制 MANIFEST.MF 文件,指定入口点(Main-Class)或其他元数据。
  • 常见场景:
    1、生成普通的 JAR 文件。
    2、为 JAR 文件添加元数据(例如 Main-Class 或 Premain-Class)
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>3.2.0</version>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>com.example.MainClass</mainClass> <!-- 主类 -->
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>

生成的文件:

target/my-app-1.0-SNAPSHOT.jar(标准的 JAR 文件)

如感兴趣,点赞加关注,谢谢!!!


journey
32 声望20 粉丝

引用和评论

0 条评论