zoukankan      html  css  js  c++  java
  • JAVA生成(可执行)Jar包的全面详解说明 [打包][SpringBoot][Eclipse][IDEA][Maven][Gradle][分离][可执行]

    辛苦所得,转载还请注明: https://www.cnblogs.com/applerosa/p/9739007.html 

     

    得空整理了关于java 开发中,所有打包方式的 一个操作方法, 有基于IDE的,有基于构建工具的.

    这里还是比较建议新手朋友尽快习惯 maven 和 gradle 等构建工具自带的打包方式. 不是说逼格高,的确是因为不依赖 IDE, 配置好 一两行命令就搞定. 离开IDE 照样出包.

     

     

    大概分为这几个步骤 

    一.  关于Jar 包(example.jar) 的 结构/作用/使用 说明

    二.  不依赖IDE和构建工具生成一个简单的 Jar 包

    依赖编译器

    三.  基于IDE( Eclipse /IDEA)生成 jar 包 

    四.  基于IDE( Eclipse /IDEA)生成可执行 jar 包

    只依赖构建工具

    五.  基于Maven 生成 Jar 包[第三方依赖包和代码文件放在一起, 为一个包] [fat-jar]

    六.  基于Maven 生成 Jar 包[分离第三方依赖包, 独立存放在 *_libs 中][推荐]

    七.  基于Gradle 生成 Jar 包  [第三方依赖包和代码文件放在一起, 为一个包] [fat-jar]

    八.  基于Gradle 生成 Jar 包  [分离第三方依赖包, 独立存放在 *_libs 中]

    注意事项:

    1. 项目均为简单项目,不存在不懂得情况,代码相关废话不说;
    2. 第三条中的项目,是一个简单的工具类集合.(就是把工具类打成一个JAR 包,方便其他项目使用,如我们使用的大多数第三方类库)
    3. 第四五六七八条 中的项目均为同一个简单的SpringBoot项目,构建方式不同而已

    本文用的jar包查看工具: JD-GUI.jar

      使用方式:右键>打开方式> Java(TM) ...

      官网:  http://jd.benow.ca/  (JD-GUI的Tab栏有Download,里面提供独立版本,eclispe/idea插件版本)

      

    一.  关于Jar 包(example.jar) 的详细说明

     JAR(Java Archive File),Java 档案文件.通常jar 为压缩文件, 与 ZIP/RAR 压缩文件 一样的概念,区别在于 jar 文件中存在一个名为META-INF/MANIFEST.MF 的清单文件,

    关于JAR包的描述信息、启动时的配置信息和安全性信息等均保存在其中,可以理解为 jar 的一个'配置说明文件'

     以spring-boot-starter-2.0.5.RELEASE.jar为例,用工具打开

     

     一般都会存在一些属性,某些属性只是为了说明jar的信息,还有一些属性,时为能够让jar正常的执行里面类的功能,比如mysql 的 jar 包 :mysql-connector-java-8.0.11.jar 里面就一堆属性.

     下面选几个用的到属性说一下,没有的参照官方文档: https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html

     基础属性:

    Manifest-Version: 用来定义 manifest文件 的版本,例如:Manifest-Version: 1.0
    
    Created-By: 该文件的生成者,一般该属性是由jar命令行工具生成的,例如:Created-By: Apache Ant 1.8 .2
    
    Signature-Version: 签名版本
    
    Class-Path: 依赖项列表,若存在多个依赖项时则采用空格分隔。依赖项路径为以JAR包路径为参考系的相对路径, 有个小细节就是, 如果自己生成这个文件,在引用了所有的以来后, 后面还有一个 '.', 对,一个点;

    可执行属性:

    Main-Class: main函数所在的全限定类名,该类必须是一个可执行的类,可以侠义理解为存在 main()函数的类

    一旦定义了此属性,即可通过 java -jar example.jar 来运行此jar包

     

    无关紧要的属性,看看就行,用到了再找:

    还有关于其他的jar的相关的: JAR包结构,META-INF/MANIFEST.MF文件详细说明[全部属性][打包][JDK]

    说了这么多,意思就是这个文件挺重要的,有时候不能运行的时候,可以考虑检查一下jar包.

      

    二.  不依赖IDE和构建工具生成一个简单的 Jar 包

    这里我们以简单的demo做例子.

    我们知道在所有的 *.java 文件都会经由JDK编译后生成一个相应的 *.class文件, 通常我们所使用的第三方类库,和我们所发布的代码一般都是 *.class文件.

    示例1: ExampleMain.java

     

     Example.java

     

     进入文件所在文件夹, 鼠标不选中文件,位于空白处, Shift+鼠标右键, 在此处打开CMD/PowerShell 窗口.(进入cmd , cd 命令切换到目录都可以)

    命令行中执行:  javac 文件名.java  即可将 *.java 编译为 *.class文件,如下图:

     

    下面我们来说打包.

    关于JDK中的打包命令在CMD中输入jar即可查看,如下图:

     

    以我们上面创建的Example.*  ExampleMain.* 为例:

    切回上级 cn 目录,执行命令:  jar cf example01.jar cn 

     

    我们来看一眼这个example01.jar 里面的东西:

     

     cn中文件很好理解,因为我们编译完成本身就有4个文件,关于这个META-INF , 是打包时jdk自动加入进去的,里面保存了一些基础属性,关于这个文件有疑问可以去看上面那个写介绍jar包结构的.

    一个很简单的jar就完成了. 正常情况打包的时候,我们会删除 *.java , 用的是编译出的*.class 文件.

    上面这个例子打出的jar包为"类库"概念的包,就是你可以导入使用,导入后,可以直接调用Example中的someMethod() 方法;

    下面说可运行jar包

    我们的ExampleMain 中包含了一个main()函数,即有一个程序入口. 我们知道关于jar包的META-INF文件夹jdk会自己生成,当然也可以自己指定.

    在某个位置(只要你找得到)下新建一个mainfest 的文件(名字随你起),里面输入相关的属性信息:

     

    这里指定了一个程序入口,就是我们说的Example.java 中的 main() 方法. 这里就需要用到jar 参数中的 -m 参数,指定清单属性信息;

    打包语句:  jar cmf [mainfese文件] example02.jar [指定的*.class 目录] 

    然后就可使用  java-jar example02.jar  执行这个jar包,会输出我们前面编写的打印语句

    请格外关注这个Class-Path: 这个属性是依赖环境选项,最基础的可运行jar包 都会存在这个属性,就好比运行程序需要JRE 环境一样.

    比如我们的一个web应用, 会在这个地方引入所有的引用的第三方jar包.

    另外,请格外注意这个 "点",就是Class-Path 后面这个点(".") .

    三.  基于IDE ( Eclipse / IDEA) 生成 jar 包    

    四.  基于IDE ( Eclipse / IDEA) 生成可执行 jar 包

    这两条放在一起说吧,因为都是依赖IDE的功能生成的,很方便,也不需要手动配置清单文件.

    jar 包现在我们大致分为两类,一类为之提供"类库"的功能型包, 一类为可运行的包(大多数情况的需求);

    下面我们新建一个简单的springboot项目,因为是demo, 就利用springboot官网提供的在线快速生成工具了,当然也可以自己创建项目.

    工具地址:  https://start.spring.io/

     

    下面是具体的打包教程:

    补充一点,如果打包时不需要把配置文件/静态文件打入jar包,Eclipse下可以把src/main/resources 右键Build Path> Remove 就可以,IDEA 下在选择编译输出目录时取消resources 的勾选即可

    导入之后的文件目录结构:

     

    他会自动生成程相关demo文件和配置文件,配置文件需要自行添加配置

    我们简单写个配置和controller 测试

     

    启动项目,浏览器访问:localhost:8080/demo, (缺省端口为8080) 浏览器会返回我们的测试数据,程序demo通过.

    下面打包:

    Eclipse:

    方法:

    项目上右键 > Export > 选择需要到处的jar包类型 (JAR file/ Runnable JAR file) > 填写相关信息 > Finish 
    “类库”型的选择: JAR file
    可运行的选择  : Runnable JAR file

    我们分别导出两种包做比较

    第一种:无法启动,类似于”类库型的”

     

     

    第二种:导出我们的可运行的jar 包 .(大多数情况是这种,用于项目发布部署等)

     在到处界面选择 Runnable JAR file (绝大多数的选择)

     

    下面对比一下两个jar包

    第一种”类库”方式导出的程序,只能提供给哦其他程序通过引用来使用相关的类功能,不能作为程序启动

    第二种 Runnable JAR file 方式的, 可以看见在清单文件中,Claa-Type:中引用所有依赖的jar 包,同时拥有Main-Class 程序入口,可以在当前目录进入cmd 命令行,使用 java -jar *.jar 来启动

     

    附上第二种jar包的启动结果

     

    IDEA:

    利用项目的 Artifacts (构建,蛮好用的功能)可以轻易实现这个功能, 他里面更多的是手动定制,比如指定mainfest 清单文件/输出的*.class 文件等.

    我们的两种jar都是基于这种方式.这里详细介绍可运行的方式,”类库”工具类性的一个道理,甚至更简单,取消一些的导出文件即可

    方法:

     菜单栏File > Project Structure(也可以使用快捷键 Ctrl+ Shift +Alt +S) > 配置好Artifacts 保存> 菜单栏Build > Build Artifacts > 然后点击操作 

     

    选择 项目设置 Project Setting 下面的 构建 Artifacts , 点击+号新建一个Artifacts 

    然后配置相关的构建属性

    这里如果只是构建”类库”型的jar包,大可以选择第一种JAR包方式还简单一些

    中途在配置相关属性的时候,需要注意两个问题:

    1. IDEA的版本问题: 选择other 类型的构建时,导致不能在jar 包添加mainfest文件

    2. 关于mainfest 文件的配置中 class-type: 他是不会添加文件夹前缀,可能需要手条件一下

     

    配置好大概是这么个样子:

     

    添加完成以后,就可以点击确定了;

     执行构建,输出jar包

     

    然后选择我们相关 Artifac > build 即可.

    然后就会在配置的输出目录内看到这个example-runnable.jar 文件了

    结果如下:

     

     下面4个方法,其实也是依赖工具的构建功能

    五.  基于Maven 生成 Jar 包  [第三方依赖包和代码文件放在一起, 为一个包] [fat-jar]

             优点: 简单,无脑

             缺点: 包体积过于大,包含所有第三方依赖包和配置文件,每次更新内容过大

             这个过于简单,不提供操作截图

             方法: 在项目文件夹下进入命令行 执行下面两条mvn 命令即可

                   mvn compile     

                   mvn pakage 

                  执行完毕之后会在 target 文件夹下生成一个 jar ,这个jar包含了所有的第三方依赖包,清单文件,我们的项目内容,用JD-GUI.jar 工具打开,就能看见所有结果文件,一目了然

    六.  基于Maven 生成 Jar 包  [分离第三方依赖包, 独立存放在 *_libs 中][推荐]

        优点: 只需要在pom.xml配置, 然后 配置文件/静态文件分离,主程序代码单独为一个jar包,更新方便推荐方式

        缺点: 需要pom.xml 的maven 配置

        关于pom.xml配置如下,需要点开+号查看

        配置完成之后, 项目目录下执行,即可输出:   mvn compile      mvn pakage

    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <finalName>example</finalName>
       
        <resources>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.jar</include>
                </includes>
            </resource>
        </resources>
    
        <plugins>
            <!--编译-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
                <configuration>
                    <fork>true</fork>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <!--用以生成jar包的-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>3.1.0</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!--区别于maven本身生成的构件,加上相关后缀-->
                    <classifier>release</classifier>
                    <!--排除的文件以及目录,这个是以class为当前目录的-->
                    <excludes>
                        <exclude>picture/**</exclude>
                        <exclude>mapper/**</exclude>
                        <exclude>**.yml</exclude>
                        <exclude>**.xml</exclude>
                    </excludes>
    
                    <archive>
                        <!--这里是添加当前目录到classpath的依赖-->
                        <manifestEntries>
                            <class-path>.</class-path>
                        </manifestEntries>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <!--这个就是清单文件中classpath的前缀配置,比如你把所有jar包放入example_lib文件夹中,这里就配置example_lib-->
                            <classpathPrefix>example_lib/</classpathPrefix>
                                     <!--程序入口,main()所在文件的全限定类名-->
                            <mainClass>cn.lnexin.demo.ExampleApplication</mainClass>
                            <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                            <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                        </manifest>
    
                    </archive>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>
                                copy-dependencies
                            </goal>
                        </goals>
                        <configuration>
                            <!--第三方将jar要导出的文件路径-->
                            <outputDirectory>${project.build.directory}/toufang_lib</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    详细的pom.xml 配置

     

    关于Gradle的两种操作新开一篇文章,更新了会贴上链接

    七.  基于Gradle 生成 Jar 包  [第三方依赖包和代码文件放在一起, 为一个包] [fat-jar]

    八.  基于Gradle 生成 Jar 包  [分离第三方依赖包, 独立存放在 *_libs 中]

  • 相关阅读:
    470. 用 Rand7() 实现 Rand10() 采样
    165. 比较版本号 字符串
    Java 通过属性名称读取或者设置实体的属性值
    双非Java的学习之旅以及秋招路程
    【Unity3D】不可读Texture资源的获取
    java 8 Map 之merge用法
    Jmeter-计数器的应用
    Jmeter-集合点【同步定时器】应用
    2. Go并发编程--GMP调度
    Go序列化嵌套结构体
  • 原文地址:https://www.cnblogs.com/applerosa/p/9739007.html
Copyright © 2011-2022 走看看