热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

javajre打包_Java精简Jrejar打包成exe

#开始最近几天都在忙一个事情,那就是尝试精简jre,我想不明白为什么甲骨文官方不出exe打包工具网络上精简jre的文章很多,但是原创的似乎没几个,绝大多数都是转

#开始

最近几天都在忙一个事情,那就是尝试精简jre,我想不明白为什么甲骨文官方不出exe打包工具...

网络上精简jre的文章很多,但是原创的似乎没几个,绝大多数都是转发同一个博客, 这里借鉴了不少思路以及方法 不知道还算不算原创了

这两天收获也是挺大的,在这里和大家分享一下我的成果.以及原理....

谢谢网络上大神们分享的教程受益良多 : )

虽然这篇博文比较长 但是实际上是因为我太啰嗦了........并不难做 并且建议先看一遍大体流程

#成果

ecf0f45abd583325e76beb3cb67e2e05.png

这个是我前不久写的一个聊天室的客户端, 源码在这里 : https://github.com/LonelySinging/JavaChatRoom-client.git

整个jre以及成品jar包加起来打包成exe之后只有11MB了 不过 说真的 还是觉得很大 因为jar包本身只有13KB 那么也就是说 jre环境是真的很大了 完整的jre是197MB了 QAQ

#开始

那么现在就开始吧

假设现在我们有

1. 需要打包的jar包 (我这里是client.jar)

2. 一台装有Java环境的win10 64位电脑 JDK是1.8版本

3. 能运行java代码的环境 (我这里是eclipse)

4. 火绒剑(我是内置版的)

5. notepad++

#分析jre目录 (我也才刚学习java没多久 对于原理性的东西了解的也不多 所以出错了别打我 QAQ)

ed3d2a9874362ed6638587747a0cb1c7.png

这是jdk1.8里面的jre目录 最主要的就是bin和lib目录

#bin目录

bin目录就是java.exe等几个命令所在地了,应该也是JVM虚拟机的本体所在, 我的里面是这样的

062ed086958ae16f3e7f5cbedeaad2da.png

这里有 java.exe 也即是启动jar的关键所在 以及一大堆的dll文件 精简bin目录的关键就是精简这些dll文件,思路就是满足java.exe的运行就可以了

那么 接下来就是想办法知道java.exe到底依赖那些dll了

#lib目录

我的lib目录是这样的

40ccbd51d3aa8612191673734a4d900c.png

大家打开可以看到是一堆不知用途的文件以及各种jar包 那么这里的jar包里面就是我们在写代码的时候调用的类以及方法.

还有字体文件(font文件夹里) 图标资源(images文件夹里面) 还有一个最大的rt.jar文件 大小居然都是60多MB了 所以 精简lib目录的核心就是精简rt.jar文件

精简的思路依旧是删除不需要的就好了

#精简开始

#精简bin目录

1. 把准备打包的jar包复制到bin

2. 新建一个批处理文件(新建文本文档) 添加内容如下 (意思是 运行jar文件 并且把所有输出信息导出到class.txt文件里)

java -jar -verbose:class client.jar >> class.txt

保存 更改名字为 run.bat (注意 这是改了后缀名的 如果没有后缀名 看下面)

fc4438f31842dad950ee4ded43e2eba7.png

3. 双击运行 run.bat 然后对你的应用进行各种操作 是所有的功能都使用一遍(这里指的是,即使是一个编辑框 你也要尝试输入不同的东西 使用方向键操作光标等等 )这个非常重要!!!!!!!!!!! 为的是把所有使用到的类都输出到class.txt文件 (class.txt文件是用来精简lib目录的 这里不管他)

4. 打开火绒剑 (其他的行为检测软件也可以 作用相同就行)  点击进程 -> 然后选择java.exe 然后就可以找到java.exe加载的所有dll文件

62335e5954931b10691280fa337182d0.png

5. 新建一个在桌面上新建一个文件夹 然后 新建两个文件夹(bin和lib) 如图

c1934b4004100d86405678475f2dc0fd.png

6. 在上面火绒剑里面查看所用到的dll以及他们的路径 找到他们 复制到新建的文件夹里的bin文件夹 得到如下 发现瞬间少了很多 (如果不是jre目录下的dll文件不复制)

030a7af559104ff5b6f993fe2605a930.png

7. 在上图空白处按着shift然后右键菜单 在此处打开power shell 运行得到如下结果 原因是缺少jvm.cfg 这是JVM虚拟机的配置文件 然后直接复制完整的jre的lib目录下的所有文件到自己精简的lib目录下

然后再次运行一次./java (值得注意的是 power shell的话 必须加上./ 才会从当前目录下找文件)

做完这些之后 应该是可以在这里运行你准备打包的jar文件的

在bin目录下新建一个批处理文件 内容如下

java -jar client.jar

pause

复制你的jar文件 在这里我的是client.jar

双击run.bat就可以 运行你的jar文件了 如果不行 就是jar文件的原因

2606fb0e14d7fbe6ab6882c6b16b04f4.png

8. 如果都可以了 那么 bin目录终于精简完了 TAT (打字好累)

#精简lib文件夹

1. 这里我做的比较水...我对lib文件夹不是太了解 所以精简的方法可能比较低级

2. 思路就是 上面不是可是已经能够运行jar文件了吗 那么 我们删除一个文件 就运行一次(这就是上面用批处理运行jar的原因 QAQ )

3. 主要是删除jar文件 从大到小 还可以尝试删除一些其他的文件 比如图片文件 字体文件 不过可能会引起一些bug

4.  这是我删除之后

b07743bcadfe81a124d21f6c43f7df6a.png

5. 这样的话 这是比较笨的方法 但是效果也还不错 然后我们发现 最大的就是rt.jar文件了 那么接下来就就是精简rt.jar

6. 拓展方法 我在看博客的时候发现可以从class.txt文件里面找到用到的jar文件 但是,,,并不能记录不是jar的文件  有些文件可能是配置文件 丢失了就不能用了 不过有人会的话 请在下面留言一下 我更新

#精简rt.jar文件

1. 记得上面的到的class.txt文件吗,把他复制到与你新建的jre目录下 也即是与bin和lib目录同目录 (这里是为了方便 不复制也行)

2. 现在 处理class.txt文件 用notepad++打开它 你会发现会有好多好多的东西TAT 我就被这个吓到了 但是没关系 接下来用notepad++的话 就会很简单

3. 删除掉所有的 不带方括号的行

4. Ctrl + F 然后搜索  "[Opened "   然后把所有带"[Opened "个的行删除掉 (是删除一整行)

5. Ctrl + F 然后搜索  "[Loaded "  点击计数,然后点击替换选项卡 全部替换 (替换的时候注意点一下计数,对比一下行数 应该是一样的,,,,)

6. 点击"正则表达式"的单选框 在查找目标里面填上正则表达式 点击计数,然后 替换->全部替换

2b0c9f2afb3116c829ea6a6d30e76c06.png

7.这样 我们就得到了如下的东西 保存

30fc358ae02a0bcdda916d0b64aa299e.png

8. jar文件本质上是zip文件 那么 我们把rt.jar文件复制到class.txt同一个目录 这样的话 精简的jre目录下就有 bin、lib、class.txt、rt.jar文件或文件夹了 然后右键 "解压到rt/" (我这里用的360压缩) 这样我么就得到了一个rt文件夹 里面是rt.jar的完整内容

9. 然后新建一个文件夹名字是ort文件夹 用来放需要的class文件

10. 然后执行如下代码 这些代码是复制别人博客的 再次非常感谢原作者 [https://blog.csdn.net/kkkwewewaqsdfas/article/details/11829349?t=1489849302000] :

记得修改第一行 package ch1;

另外 代码中的InputOutput那个会出错 因为缺少那个类 在上面原作者的链接里面可以找到InputOutput的java文件

原作者的 InputOutput文件里面的main()方法会出错 删除即可

2019年2月15补充: 如果不行折腾 以下代码已经编译成jar包 可以直接运行: 需求类复制工具 点击下载即可 运行就知道怎么用了

packagech1;

importjava.io.BufferedReader;importjava.io.File;importjava.io.FileInputStream;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.LineNumberReader;//import InputOutput;

/***@authorknowyourself1010

**/

public classCopyUsefulClasses {//文件拷贝

private static booleancopy(String sourceFileLocation,

String objectFileLocation, String fileName) {try //must try and catch,otherwise will compile error

{if (sourceFileLocation.substring(sourceFileLocation.length() - 1) != "/") {

sourceFileLocation+= "/";

}if ((objectFileLocation.substring(objectFileLocation.length() - 1)) != "/") {

objectFileLocation+= "/";

}

InputOutput inputOutput= newInputOutput();byte[] b =inputOutput

.DataOutputFully(sourceFileLocation, fileName);

inputOutput.DataInputFully(objectFileLocation, fileName, b);return true; //if success then return true

}catch(Exception e) {

System.out.println("Error!");return false; //if fail then return false

}

}//读取路径,copy

private static intdealClass(String needfile, String sdir, String odir)throwsIOException {int sn = 0; //成功个数

if (odir.length() > 0 && sdir.length() > 0) {if ((sdir.substring(sdir.length() - 1)) != "/") {

sdir+= "/";

}if (odir.substring(odir.length() - 1) != "/") {

odir+= "/";

}

File usedclass= newFile(needfile);if(usedclass.canRead()) {

String line= null;

LineNumberReader reader= newLineNumberReader(new InputStreamReader(newFileInputStream(usedclass),"UTF-8"));while ((line = reader.readLine()) != null) {

line=line.trim();if (line.contains(".") || line.contains("/")) {//format the direction from package name to path

String dir = line.replace(".", "/");//filter the file name.

String tmpdir = dir.substring(0, dir.lastIndexOf("/"));

String sourceFileLocation= sdir +tmpdir;

String objectFileLocation= odir +tmpdir;

String fileName=dir.substring(

dir.lastIndexOf("/") + 1, dir.length())+ ".class";

File fdir= newFile(objectFileLocation);if (!fdir.exists())

fdir.mkdirs();boolean copy_ok =copy(sourceFileLocation,

objectFileLocation, fileName);if(copy_ok)

sn++;else{

System.out.println(line);

}

}else{

sn= -1;

}

}

}

}returnsn;

}/***@paramargs*/

public static voidmain(String[] args) {//TODO Auto-generated method stub

try{

BufferedReader lineOfText= null;//get need classes log file direction

System.out

.println("要读取的class.txt文件的绝对路径 :");

lineOfText= new BufferedReader(newInputStreamReader(System.in));

String needfile=lineOfText.readLine();//get source folder direction

System.out

.println(needfile+ "\n输入jre/lib/rt.jar解压後的rt文件夹所在的路径 :");

lineOfText= new BufferedReader(newInputStreamReader(System.in));

String sdir=lineOfText.readLine();//get object folder direction

System.out

.println(sdir+ "\n再输入ort(所要存放拷贝过来的有用的.class文件的文件夹):");

lineOfText= new BufferedReader(newInputStreamReader(System.in));

String odir=lineOfText.readLine();

System.out.println(odir+ "\n");int sn =dealClass(needfile, sdir, odir);

System.out.print(sn);

}catch(IOException e) {//TODO 自动生成 catch 块

e.printStackTrace();

}

}

}

运行的时候填写这样的内容

bc2e27419874aed214d64504ebea3bfa.png

首先输入usedClasses.txt的绝对路径,回车,在输入jre/lib/rt.jar解压後的rt文件夹所在的路径,回车,再输入ort(所要存放拷贝过来的有用的.class文件的文件夹)。然后等上几分中,期间会提示,你的产品程序所用到的jre不包含的类不存在,不用管,因为我们呢只拷贝rt文件中的.class文件 (这一段话复制自上面代码所在博客)

11. 这样的话 在ort文件夹里面就有了很多文件夹 像是java、javax什么的 全选这些文件夹 右键 添加到 ort.zip

11.5: 将ort打包的方法还有一个 将cmd工作目录切换到 有[ort]文件夹的哪里 然后执行命令 [jar cvf rt.jar -C ort/ .] (方括号里面的全部内容) 即可 方法来自评论区:水瓶座鬼才

12. 得到ort.zip文件之后改名为rt.jar

13. 删除lib目录下的rt.jar文件 用上面的rt.jar文件(也就是我们自己打包的)替换

14. 在bin目录下运行run.bat文件 然后如果成功了就测试一下各种功能 确认没问题的话 jre环境就已经精简成功了 可以直接看下面的exe打包阶段了

15 如果有错误 应该是这样的 那么应该是这样的 这里的话 明显是class文件缺失

3707053d7c672791628f27b3ec30e61c.png

16. 在精简的rt.jar文件上面右键 用360压缩打开

17. 打开之前解压的rt.jar文件夹(完整的rt.jar文件解包之后的rt文件夹)

18. 根据上图中提示的丢失class文件的路径, 在360压缩窗口和rt文件夹中找到丢失的class文件 然后拖到360压缩窗口里 需要保证class文件的位置是一样的 (比如在rt文件夹里面的class文件路径是java/lang 目录下 那么在360压缩里也应该是这个目录)如果添加出错 那就关闭上图的窗口

19.  再运行bin目录下的run.bat批处理文件 可能还会有错 有错的话 就继续上一个步骤 直到没有错误

20. 这样的话 jre环境就已经精简成功了 : ) 接下来就是打包成exe了

#打包成exe

1. 这个就比较简单了 使用现成的工具就可以了 就是      winrar

2. 不过呢 这个软件似乎是没有执行命令行的作用的 解决方法就是用C语言写一个启动器 QAQ  (其他语言也行 只要是个exe就行了) 但是呢 直接用C语言执行 java -jar client.jar 这个命令会有一个问题 就是会有一个控制台窗口 (我这里是图形界面 如果没有图形界面的话 那就不用考虑了)  这个据说用javaw 运行就没问题 不会出现控制台窗口 但是我失败了/QAQ 不知道为啥 所以接下来需要这样做

3. 编译一个exe文件 C语言代码如下  说明一下 C语言如果是控制台程序的话 运行的时候还是有控制台窗口的 所有建立的工程是win32工程 也就是默认带窗口的那种 如果有小伙伴不知道怎么弄 请在下面留言 我会补充一下

#include "stdafx.h"#include"无窗口的vbs运行.h"

intAPIENTRY _tWinMain(_In_ HINSTANCE hInstance,

_In_opt_ HINSTANCE hPrevInstance,

_In_ LPTSTR lpCmdLine,

_In_intnCmdShow)

{

system("run.vbs");return 0;

}

核心代码就是是system("run.vbs");

4. 那么接下来就编写run.vbs 内容如下 作用是运行一个名为run.bat的批处理 并且把窗口隐藏起来

Set ws = CreateObject("Wscript.Shell")

ws.run"cmd /c run.bat",vbhide

5. 修改bin目录下的run.bat文件 修改内容如下 然后复制到与bin、lib文件夹同目录

cd bin

java-jar client.jar

6. 上面两步完成了GUI界面Java程序 隐藏控制台窗口运行 然后把上面编译的启动器exe放在与bin、lib文件夹同目录 最终是这样的 双击run.vbs或者启动器.exe应该都是可以无控制台窗口运行的

b41744343c23271e82b3e0e7a24f5af6.png

7. 终于到了最终打包的时候了 TAT  下载winrar 安装

8. 全选上图所有的文件及文件夹 压缩为rar格式的压缩包

9. 用winrar打开rar压缩包 然后选择自解压格式

df1331f19fd4c7d856af4344f641b680.png

11c40effd8021f7848b8f88e2fc33f50.png

90a8ef619e22ab5690e864a89e53c72d.png

10. 然后点击确定 再点确定 就可以得到 在上图高级设置里面还可以修改生成exe的图标

ecf0f45abd583325e76beb3cb67e2e05.png

看到了吗 整个环境加上 jar打包成exe之后只有11MB 不到了

最终  双击运行一下 TAT 惊喜的发现 成功了!!!!!!!!!!!!!!!!!!!!!!!!!!

如果不能打包成功 请打开  https://blog.csdn.net/fz835304205/article/details/46942589

可以看看这个博文 谢谢这位博主分享经验 ^_^

#期间可能遇到的问题

1. class文件丢失太多了 这个主要是在生成class.txt文件的时候没有把所有程序功能使用一遍造成的 所谓的使用包括点击窗口 以及各个组件的功能

2. 在往rt.jar文件里面添加class文件的时候添加不进去 这个可能是因为你的程序还在运行 需要关闭控制台窗口

3. 有时候可能往rt.jar里面添加class文件也不能解决问题 那么就把相关的整个文件夹替换进去

4. 完成之后你的程序可能会有各种bug那么 你得让控制台窗口出来 然后查看异常 看看丢失了那个class文件 把他 添加到rt.jar中相同的文件夹下

5. 打包完了发现不能双击运行提示丢失DLL文件 那么 你得安装运行库 百度运行库合集就可以了

6. 这样精简的jre对其他系统(win7 winxp)的兼容性比较差 甚至不能运行 解决方案就是在目标系统上运行一次 得到class.txt 整合所有用到的class文件应该就可以了(其实我这个没有尝试 是个思路)

7. 如果还有问题请在下方留言 有建议也请留言 谢谢 : )

感谢以下几篇文章:

https://blog.csdn.net/kkkwewewaqsdfas/article/details/11829349?t=1489849302000

https://blog.csdn.net/xiaoping8411/article/details/6973887

https://blog.csdn.net/ema1995cylove/article/details/52792361

https://blog.csdn.net/fz835304205/article/details/46942589 (winrar打包方式)

还有几个没收藏 谢谢了 ^_^

-------转发请写明出处 谢谢



推荐阅读
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。 ... [详细]
  • 解决JAX-WS动态客户端工厂弃用问题并迁移到XFire
    在处理Java项目中的JAR包冲突时,我们遇到了JaxWsDynamicClientFactory被弃用的问题,并成功将其迁移到org.codehaus.xfire.client。本文详细介绍了这一过程及解决方案。 ... [详细]
  • Struts与Spring框架的集成指南
    本文详细介绍了如何将Struts和Spring两个流行的Java Web开发框架进行整合,涵盖从环境配置到代码实现的具体步骤。 ... [详细]
  • 获取Jedis和Commons Pool JAR包的两种方法及详细步骤
    本文介绍如何通过网盘链接或官方网站获取Jedis和Commons Pool的JAR包,并提供详细的图文教程。同时,还附有导入JAR包到项目的相关建议。 ... [详细]
  • 阿里云ecs怎么配置php环境,阿里云ecs配置选择 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 本文详细探讨了Java中的ClassLoader类加载器的工作原理,包括其如何将class文件加载至JVM中,以及JVM启动时的动态加载策略。文章还介绍了JVM内置的三种类加载器及其工作方式,并解释了类加载器的继承关系和双亲委托机制。 ... [详细]
  • Logback使用小结
    1一定要使用slf4j的jar包,不要使用apachecommons的jar。否则滚动生成文件不生效,不滚动的时候却生效~~importorg.slf ... [详细]
  • 简化报表生成:EasyReport工具的全面解析
    本文详细介绍了EasyReport,一个易于使用的开源Web报表工具。该工具支持Hadoop、HBase及多种关系型数据库,能够将SQL查询结果转换为HTML表格,并提供Excel导出、图表显示和表头冻结等功能。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 当 WebLogic 连接的数据源数据库密码发生更改时,需要在域目录的 config 文件夹下的 jdbc 配置文件中更新相应的密码。本文将详细介绍如何安全地修改和验证这些配置文件中的加密密码。 ... [详细]
  • ssm框架整合及工程分层1.先创建一个新的project1.1配置pom.xml ... [详细]
  • Spring Boot 中静态资源映射详解
    本文深入探讨了 Spring Boot 如何简化 Web 应用中的静态资源管理,包括默认的静态资源映射规则、WebJars 的使用以及静态首页的处理方法。通过本文,您将了解如何高效地管理和引用静态资源。 ... [详细]
  • 本文详细介绍如何使用 Apache Spark 执行基本任务,包括启动 Spark Shell、运行示例程序以及编写简单的 WordCount 程序。同时提供了参数配置的注意事项和优化建议。 ... [详细]
author-avatar
LordHo
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有