Java开发程序,发布时总要考虑的问题就是怎么在使用者的机器上装好JRE。要考虑的问题很多:使用者有没有能力独自安装JRE,使用者已有的 JRE 和我们需要的版本是不是一致,会不会出现版本问题,等等。使用.NET要考虑的问题就少些。现在.NET CLR似乎已经很普及了,看好多D版的 Win XP都会自己安装最新的.NET CLR,而且似乎它的安装界面也比JRE友好些。彻底解决安装JRE的问题的方案,就是让我们的应用程序自己背着JRE!这样,我们的程序就像传统的Win32应用程序一样,双击就可以执行,不用管所在的机器上是否有JRE,是什么版本的JRE,无论怎样,我有我自己的!要做到这一点,其实非常容易。
王森在他的《Java深度历险》(强力推荐这本书,内容少而精)的第一章就解释了JDK,JRE,JVM之间的关系。解释了我们执行java.exe时发生的事情。其中提到,java.exe依照一套逻辑来寻找可以用的JRE,
1、首先查找自己所在的目录下有没有 JRE(据王森讲这样说不确切,我没有JDK全部的源代码,在此无从考证);(注:经过我的实际验证,在windows2003+jdk 6的条件下,java.exe不会在自己的当前目录下寻找JRE目录)
2、其次查找自己的父目录下有没有JRE;(注:当时实验时就这个问题郁闷了半天,原因是开始我把JRE理解为泛的java运行环境概念,而java.exe需要用的内容都在/JRE/LIB目录下,所以我把这个目录的内容放在父目录下,但是不起作用。后来才知道,JRE是固定的目录名称而且必须使用这个名称,并且必须将JRE安装目录下的内容都复制过来才有效。也就是说,java.exe必须要在.../windows/底下找到JRE目录,否则就按第3的逻辑找注册表。sign :-( )(再注:父目录仅指上一层,在往上就不是啦)
3、最后才是查询Windows的注册表(注:HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment)。
注1:思维发散---我这个人考虑问题总是这样,容易涣散。java.exe的版本必须和他找到的JRE版本相匹配,否则会有错误。例如,安装了JDK 6,在console下键入java -jar -verbose pw.zfb.jar, 自然就会用system32目录下的java.exe执行, 并且在当前目录和父目录下没有找到JRE,于是察看注册表发现,CurrentVersion的值是1.4(该值可能被修改了),于是继续在1.4的键值中找到JavaHome,从他的值中得到JRE的路径,于是,1.6版的java使用了1.4版的JRE,so, error is occured. as follow:
C:\javatest>java -jar -verbose pw.zfb.jar >tt.txt
Registry key 'Software\JavaSoft\Java Runtime Environment\CurrentVersion'
has value '1.4', but '1.6' is required.
Error: could not find java.dll
Error: could not find Java 2 Runtime Environment.
同理,如果你发布的java程序中自带了JRE,请务必保证java.exe和JRE配套运行。这样也避免了JRE不一致导致的问题。所以,开发Java程序或是执行Java 程序时,一定要記得两件事:
1. 哪一个java.exe 被執行。
2. java.exe 找到哪一套JRE。
只要这两件事情确定了,就知道问题发生的来龙去脉,也可以很容易地解決很多貌似的怪异的问题。
注2:思维发散---上面查找规则中说的“首先查找自己所在的目录下”中,自己所在的目录指java.exe所在的目录,比如,我们打开console,进入c:\根目录下,在console中直接键入c:\java.exe,如果c:的根目录下没有java.exe, 那么console怎么找到java.exe呢,肯定是通过遍历console的环境变量的path路径去查找匹配。那么我们当前的工作路径是c:\,但是,java.exe寻找JRE的规则中,是查找自己所在的目录和父目录(也就是java.exe所在的路径),而不是在当前工作路径下寻找。而对于[JDK 5.0以上默认到当前工作目录,以及JDK的lib目录中寻找Java程序(如*.class和*.jar)]中所说的当前工作目录,就是console命令行中的路径,而不是找到java.exe所在的路径。例如
L:\eclipse\workspace\JavaTest\arrays\IceCream.class 中使用了L:\eclipse\workspace\JavaTest\pw\zfb\marry.class中的类,如果我们在L:\eclipse\workspace\JavaTest\ 目录下键入 java arrays.IceCream 那么执行没有问题,因为按照[java.exe在JDK 5.0以上默认到当前工作目录,以及JDK的lib目录中寻找Java程序]这个规则他在当前工作目录下找到了marry.class。但是如果我将IceCream.class 换个位置C:\javatest\arrays\IceCream.class ,那么我在 c:\javatest下键入 java arrays.IceCream 就会说找不到marry.class. 这是设置classpath即可解决问题。C:\>set classpath=%classpath%;L:\eclipse\workspace\JavaTest。 如果要放在lib目录下,就最好先打包成jar文件,然后再设置好classpath,也可以。(可参考:开始学习java--再谈设置Path与Classpath(如何import jar中的class))
通常我们在安装好了JRE的机器上的任何一个目录下都可以执行java.exe。因为它在安装时被复制到了windows的system32目录下,而后者无论如何都会在path环境变量中。这个java.exe最终必然会访问注册表来确定真正的JRE的所在地(因为,从windows xp开始,ms宣布不再在OS中支持java,也就是不再在OS中提供JRE,所以,正常情况下,system32目录下只有java.exe,而没有JRE目录及相关内容,上层windows目录下也没有JRE目录及相关内容,所以,在他的当前目录(system32)中,以及父目录中(windows)无法找到JRE目录,安装上面总结的寻找逻辑java.exe只能去注册表中寻找)。若我们要求每一个应用程序都自带JRE,必然不能走这条路。但,逻辑的第二条讲,java.exe会在它的父目录下查找JRE,解决方案就在这一条中。
假设我们的应用程序打好了包,叫做 MyApp.jar,放在MyApp的目录下。我们在MyApp目录下,可以执行java ?jar MyApp.jar来运行我们的程序。我们安装的是 JRE 1.5,在C:\Program Files\Java\jre1.5.0下。现在,我们只需要简单的将jre1.5.0目录搬到MyApp目录下,顺便改个容易写的名字比如叫jre。现在,我们的应用程序的目录结构就象这样:
.../MyApp/
--MyApp.jar
--Jre
其中jre中是Jre1.5.0目录下的全部内容。
Java.exe 就在jre目录下的bin目录中。根据第二条逻辑,java.exe会在它的父目录中查找jre,实验证实,它会查找lib目录,而lib就在jre目录下。因此,这样java.exe就会确定jre的所在然后正常执行java程序,不会去管我们是否安装了JRE,注册表中是否有注册项这些杂事了。
试一下,在命令行下进入MyApp的目录下,假设它在C盘,将path指向MyApp下的JRE:
set path=c:\MyApp\jre\bin (这时已经将原path中的设置清空了,不会再到windows\system32下寻找,如果不清空,那么按照寻找次序,还是会先使用windows\system32下的java.exe。所以,一般情况下,自己的程序运行之前最好先在批处理文件里面临时设置PATH,把自己用的JRE放到PATH路径最前面,所以肯定会运行自己带的JRE,不会造成版本混乱。 )
然后运行:
java -verbose -jar MyApp.jar
加上verbose参数以确定我们确实用了这一套被搬出了家的JRE。
程序可以运行,并且在命令行输出的前几行,可以看到:
[Opened C:\MyApp\jre\lib\rt.jar]
[Opened C:\MyApp\jre\lib\jsse.jar]
[Opened C:\MyApp\jre\lib\jce.jar]
[Opened C:\MyApp\jre\lib\charsets.jar]
因此程序读取的确实是它的私有的JRE。
至此,我们似乎完成了任务。但是现在我们的私有JRE仍不完美,缺点是太大。JRE 1.5有接近70MB,作为我们的私有的JRE,好多内容都是可以抛弃的。Jre目录下的license都可以不要,bin下的执行文件只需要保留java.exe或者javaw.exe,lib下只要保留rt,jsse, jce,charsets几个库就可以了。除了i386和zi两个子目录外,其余的子目录都可以不要。Zi下只需要保留自己地区的子目录和其下的一些文件就可以。Lib下除了库之外的属性文件等等都要保留。这样清理一番,JRE仍然有接近50MB。还可以继续清理几个库文件里面不需要的内容,这需要仔细的整理,会很费功夫。最好能写出一个自动工具帮助我们整理它们。从Sun公司上下到的JMF里面附带的用Java写的媒体播放器就自带了JRE,只有几个 MB。
清理过后需要运行几遍我们的应用程序,以确保我们的JRE不缺少东西。
如果我们希望能有一个程序直接启动我们的应用程序,那就还要费些功夫。最简单的方法是弄出一个快捷方式来,但是快捷方式的路径不能是相对的,不方便我们安装。我想到的方案就是用Win32程序包装一下。在VS.NET下写一个Win32小程序:
int PASCAL WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpszCmdLine,
int nCmdShow )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( π, sizeof(pi) );
// Start the child process.
if( !CreateProcess( "jre\\bin\\javaw.exe",//执行的程序名,该Win32小程序是和MyApp.jar放在一个目录下
的,所以,这里使用相对路径可以指定使用自己的JRE。
同时注意,该win32程序必须在包装的路径(即MyApp\)中运行才
有效, 因为他用的是相对路径。有人问为何不用注册表?
首先,这个程序的发布是没有安装的过程的,那么我怎么知道用户
把它放在什么路经下? 如果仅是针对windows平台发布,那么
MyApp.jar 是我们真正的java程序他保证了平台无关性,而针对
windows平台的发布,我们可以使用一个win32 wrapper,设置
注册表、环境变量等win32平台特有的配置来解决
anywhere runable的问题。
"jre\\bin\\javaw.exe -jar MyApp.jar", // 带参数的执行程序
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
FALSE, // Set handle inheritance to FALSE.
0, // No creation flags.
NULL, // Use parent's environment block.
NULL, // Use parent's starting directory.
&si, // Pointer to STARTUPINFO structure.
π ) // Pointer to PROCESS_INFORMATION structure.
)
{
ErrorExit( "CreateProcess failed." );
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
基本上是按照MSDN文档中的例子照搬的。将它编译成一个EXE文件,我们的任务才全部完成。双击这个EXE文件,我们的程序启动了,看起来和传统的Win32程序没有两样,JRE完全被隐藏在底层。
相关推荐
Java Runtime Environment(JRE)是Java程序执行所需的基础组件,它是Java开发工具集(Java Development Kit,JDK)的一部分。JRE为Java应用程序提供了一个运行平台,使得开发者编写出的Java程序可以在任何安装了JRE...
Java Runtime Environment (JRE) 1.4.2 是Java应用程序执行所需的关键组件,它为开发者和用户提供了在各种操作系统上运行Java应用的基础。这个版本是Sun Microsystems在2004年发布的一个重要里程碑,它在Java技术的...
JRE则是运行Java应用程序所必需的环境,它包含了JVM和必要的Java类库,但不包括开发工具。JRE 1.8.0_181是针对Java 8的一个更新,修复了一些安全漏洞,提高了性能,并提供了更好的兼容性。用户只需安装JRE,即可在...
Java的JRE1.5,全称为Java Runtime Environment 1.5,是Sun Microsystems公司(后被Oracle收购)推出的一款重要版本的Java运行环境。它为用户提供了执行Java应用程序和Applet所需的所有组件,确保了网页上的Java内容...
Java开发工具JRE 1.4是Java平台标准版(Java SE)的一个早期版本,它为开发者和用户提供了一个运行环境来执行Java应用程序。这个版本在Java的发展历程中扮演了重要的角色,因为它引入了一些新的特性和改进,使得Java...
Java运行环境(Java Runtime Environment,简称JRE)是执行Java应用程序所必需的软件组件,它提供了执行Java字节码的虚拟机(Java Virtual Machine,JVM)以及必要的库和其他支持文件。在Java开发中,编写好的Java...
Java程序打包和制作安装包是为了让Java桌面应用能在未安装JDK的计算机上运行。通常,Eclipse中的Java项目导出为Runnable JAR文件后,需要JRE环境才能执行。以下详细介绍了整个过程: 1. **导出Runnable JAR文件** ...
在IT行业中,将Java应用程序打包成可执行的.exe文件对于那些不希望用户安装JRE(Java Runtime Environment)的开发者来说,是一项重要的任务。标题“exe调用java 脱离JRE”指的是创建一个能够独立运行的Windows可...
JRE是运行Java应用程序所必需的环境,它包含了Java虚拟机(JVM)、类库和其他必要的组件,但不包括开发工具。用户可以下载并安装JRE来运行基于Java 8的应用程序,而开发者则需要JDK来进行编码和调试。 在Java 8中,...
Java运行环境(JRE,Java Runtime Environment)是执行Java应用程序所必需的基础软件,它包含了Java虚拟机(JVM,Java Virtual Machine)以及Java类库,使得开发者编写的Java程序能够在用户的计算机上运行。...
Java JRE(Java Runtime Environment)是Oracle公司提供的Java运行时环境,它包含了执行Java应用程序所需的类库和其他必要的组件。在本例中,我们讨论的是Java JRE的第8个主要版本的更新241(8u241)。这个版本支持...
Java客户端和JRE瘦身是优化Java应用程序性能和减少资源占用的重要技术。在许多情况下,Java应用程序,特别是桌面客户端,会附带完整的Java运行时环境(JRE),这可能导致安装包体积庞大,影响下载速度和用户体验。...
Java运行环境(JRE)是执行Java应用程序必不可少的组件,JRE6,即Java Runtime Environment 1.6,是Oracle公司发布的Java平台的一个版本。这个版本在2006年推出,提供了许多新特性和改进,以提升性能、稳定性和安全...
Java运行环境JRE,全称为Java Runtime Environment,是Java编程语言的一个关键组成部分,它使得开发者编写的Java应用程序能够在各种操作系统上得以执行。JRE包含了Java虚拟机(JVM)、类库以及其他必要的组件,使得...
JRE 是 Java 应用程序运行的必要环境,它不包含开发工具,而是专注于提供运行 Java 程序所需的组件。主要包括 JVM、Java 类库以及支持 Java 应用运行的基础服务。用户只需安装 JRE 即可运行基于 Java 开发的应用程序...
Java 1.8 JDK/JRE 是Java开发工具包和Java运行环境的组合,对于任何Java开发者来说都是必不可少的基础。在本压缩包中,你将找到用于编写、编译和运行Java应用程序的所有必要组件。让我们深入了解一下这两个核心组件...
Java运行环境(JRE,Java Runtime Environment)是执行Java应用程序所必需的基础组件,它包含了Java虚拟机(JVM)、Java核心类库以及其他支持Java程序运行的必要组件。JRE-8u251是针对Windows 64位操作系统的一个...
Java JRE 1.8,全称为Java Runtime Environment,是Oracle公司提供的用于执行Java应用程序的必备组件。它包含了Java虚拟机(JVM)、类库以及其他支持Java程序运行的必要组件。JRE 1.8是Java发展过程中的一个重要版本...
mac版本安装jre运行java程序