用Java开发程序发布时总要考虑的问题就是怎么在使用者的机器上装好JRE要考虑的问题很多使用者有没有能力独自安装JRE使用者已有的JRE和我们需要的版本是不是一致会不会出现版本问题等等
使用NET要考虑的问题就少些现在NET CLR似乎已经很普及了看好多D版的Win XP都会自己安装最新的NET CLR而且似乎它的安装界面也比JRE友好些彻底解决安装JRE的问题的方案就是让我们的应用程序自己背着JRE!这样我们的程序就像传统的Win应用程序一样双击就可以执行不用管所在的机器上是否有JRE是什么版本的JRE无论怎样我有我自己的!要做到这一点其实非常容易
王森在他的《Java深度历险》(强力推荐这本书内容少而精)的第一章就解释了JDKJREJVM之间的关系解释了我们执行javaexe时发生的事情其中提到javaexe依照一套逻辑来寻找可以用的JRE首先查找自己所在的目录下有没有JRE(据王森讲这样说不确切我没有JDK全部的源代码在此无从考证)其次查找自己的父目录下有没有JRE最后才是查询Windows的注册表
通常我们在安装好了JRE的机器上的任何一个目录下都可以执行javaexe因为它在安装时被复制到了windows的system目录下而后者无论如何都会在path环境变量中这个javaexe最终必然会访问注册表来确定真正的JRE的所在地若我们要求每一个应用程序都自带JRE必然不能走这条路但逻辑的第二条讲javaexe会在它的父目录下查找JRE解决方案就在这一条中
假设我们的应用程序打好了包叫做MyAppjar放在MyApp的目录下我们在MyApp目录下可以执行java –jar MyAppjar来运行我们的程序我们安装的是JRE 在C:\Program Files\Java\jre下现在我们只需要简单的将jre目录搬到MyApp目录下顺便改个容易写的名字比如叫jre现在我们的应用程序就象这样
MyApp
MyAppjar
Jre
Jre目录下的全部内容
Javaexe就在jre目录下的bin目录中根据第二条逻辑javaexe会在它的父目录中查找jre实验证实它会查找lib目录而lib就在jre目录下因此这样javaexe就会确定jre的所在然后正常执行java程序不会去管我们是否安装了JRE注册表中是否有注册项这些杂事了
试一下在命令行下进入MyApp的目录下假设它在C盘将path指向MyApp下的JRE
set path=c:\MyApp\jre\bin
然后运行
java –verbose –jar MyAppjar
加上verbose参数以确定我们确实用了这一套被搬出了家的JRE
程序可以运行并且在命令行输出的前几行可以看到
[Opened C:\MyApp\jre\lib\rtjar]
[Opened C:\MyApp\jre\lib\jssejar]
[Opened C:\MyApp\jre\lib\jcejar]
[Opened C:\MyApp\jre\lib\charsetsjar]
因此程序读取的确实是它的私有的JRE
至此我们似乎完成了任务但是现在我们的私有JRE仍不完美缺点是太大JRE 有接近MB作为我们的私有的JRE好多内容都是可以抛弃的Jre目录下的license都可以不要bin下的执行文件只需要保留javaexe或者javawexelib下只要保留rtjssejcecharsets几个库就可以了除了i和zi两个子目录外其余的子目录都可以不要Zi下只需要保留自己地区的子目录和其下的一些文件就可以Lib下除了库之外的属性文件等等都要保留这样清理一番JRE仍然有接近MB还可以继续清理几个库文件里面不需要的内容这需要仔细的整理会很费功夫最好能写出一个自动工具帮助我们整理它们从Sun公司上下到的JMF里面附带的用Java写的媒体播放器就自带了JRE只有几个MB
清理过后需要运行几遍我们的应用程序以确保我们的JRE不缺少东西
如果我们希望能有一个程序直接启动我们的应用程序那就还要费些功夫最简单的方法是弄出一个快捷方式来但是快捷方式的路径不能是相对的不方便我们安装我想到的方案就是用Win程序包装一下在VSNET下写一个Win小程序
int PASCAL WinMain( HINSTANCE hInstance
HINSTANCE hPrevInstance
LPSTR lpszCmdLine
int nCmdShow ){STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si sizeof(si) );
sicb = sizeof(si);
ZeroMemory( &pi sizeof(pi) );
// Start the child process
if( !CreateProcess( jre\\bin\\javawexe//执行的程序名
jre\\bin\\javawexe jar MyAppjar // 带参数的执行程序
NULL
// Process handle not inheritable
NULL
// Thread handle not inheritable
FALSE
// Set handle inheritance to FALSE
// No creation flags
NULL
// Use parents environment block
NULL
// Use parents starting directory
&si
// Pointer to STARTUPINFO structure
&pi )
// Pointer to PROCESS_INFORMATION structure)
{ErrorExit( CreateProcess failed );
} // Wait until child process exitsWaitForSingleObject( pihProcess INFINITE );
// Close process and thread handles
CloseHandle( pihProcess );
CloseHandle( pihThread );}
基本上是按照MSDN文档中的例子照搬的将它编译成一个EXE文件我们的任务才全部完成双击这个EXE文件我们的程序启动了看起来和传统的Win程序没有两样JRE完全被隐藏在底层
PS 使用了这个方案后我用Wise Installation System制作安装程序发现一个非常奇怪的问题安装结束后安装程序似乎非要运行一个叫做GLJ什么什么后缀是TMP的程序还需要JVM结果就报错JVMDLL找不到安装总是不成功我已经禁掉了OCX / DLL / EXE自注册和卸载支持为什么还不对?有谁知道是为什么吗?