一
Java程序的启动过程
对于普通用户来说Java最让人不习惯的是程序的启动过程即使对于富有经验的开发者为了用默认的装载器启动Java程序不得不编写大量批命令脚本文件不得不在命令行环境下进行大量的复制/粘贴操作也很容易出现误操作
用惯了Windows方便快捷的GUI人们早就习惯了通过双击运行程序的方式对于Java程序要实现这个本机启动功能就必须编写定制的启动器用定制启动器启动Java程序不仅方便了最终用户而且使软件作品看起来更专业本文就以Windows平台为例介绍如何构造Java定制启动器
Java程序可以由任何本机运行的程序调用执行所谓Java启动器就是一个专门用来启动Java程序的本机执行程序最常见的启动器是Sun在Java Runtime Environment的/bin目录中提供的启动器就Windows平台而言它们是javaexe和javawexe前者运行时打开两个窗口一个是接收Systemout/err和启动器输出的控制台窗口另一个是Java程序本身的窗口javaw运行时不打开控制台窗口在JSE/EE平台中虚拟机以动态库的形式实现也放在/bin目录下动态库的名字在Windows中是javadll在Unix中是javaso所谓装入虚拟机就是指装入这个动态库
提供给VM的参数可以通过两种方式指定或者是在启动器的命令行参数中指定或者通过定义相应的环境变量指定只有一个参数例外要启动的类的名称只能在启动器的命令行参数中指定虽然指定方式的多样姓为人们各取所需带来了方便但不可否认地它也正是许多混乱的根源使用定制启动器能够完全避免这方面的问题
当VM结束启动类的main()方法的运行启动器调用destroy()方法释放各种资源并退出应当注意的是VM一旦开始运行我们就不能再卸载它对于Java启动器来说能否关闭VM无关紧要因为启动器会随着Java程序的退出而退出然而对于嵌入了VM的本机应用例如浏览器这意味着有一块内存被永久姓地占用不能再收回
二Windows平台的启动器
搞清楚了Java程序的启动过程我们就可以开始编写启动器的代码下面这个启动器用C++写成适合于所有Windows平台
首先就象大多数Windows程序一样启动器需要一个WinMain()入口与Windows这一特定平台相关的问题除了必要的类型转换(例如对CreateJavaVM()的转换)之外另外一个要注意的地方就是装入VM的DLL文件装入DLL文件最可靠的办法是显式地调用LoadLibrary()装入JVM之后就可以利用内核调用GetProcAddress()获得CreateJavaVM()的函数指针然后调用该指针启动VM在启动类的标识符中使用的分隔符是斜槓而不是句点即我们用javabunny/JavaBunny表示启动类而不是用javabunnyJavaBunny的形式这是因为FindClass()是一个虚拟机调用而虚拟机内部用斜槓作为分隔符随便说明一下这个例子把启动类的名字(和其他一些配置选项)直接写进了代码之中(称为硬编码)对于提供给最终用户使用的产品这种做法有其优点但对于开发环境来说这些值最好拿出来放在某个配置文件中
Java程序启动后执行的第一个方法称为启动方法通常是main()本例通过JNI调用GetStaticMethodID()获得启动方法的IDGetStaticMethodID()要求指定方法的名字(main)和方法的类型描述符(([Ljava/lang/String;)V)这个类型描述符表示方法的参数是一个字符串的数组返回值类型是void有关类型描述符的更详细的说明请参见JVM相关资料注意从这里可以看出在使用定制启动器时Java程序的启动方法不必一定是static void的main方法可以用任何方法作为Java程序中第一个执行的方法甚至包括实例方法或构造函数
示例程序中最后一个需要注意的地方是jvm>DestroyJavaVM()调用从表面看起来这个语句似乎是程序执行后进行清理工作的方法可有可无其实不然如果Java程序是多线程的在调用这个方法时程序仍旧在运行例如对于一个运行着的Swing程序如果它的main方法结束DestroyJavaVM()的执行将被阻塞直至所有非守护线程都执行完毕所以这行代码是必不可少的如果省略这行代码则当主线程执行完毕即使其他线程(例如Swing GUI的事件循环)仍旧在运行整个程序也会立即退出
三配置和使用
如前所述这个启动器以硬编码的方式指定了启动类的名字但是没有一个路径是硬编码的这是定制启动器的优点之一由于所有的路径都是相对的用户可以把整个Java应用从一个文件夹拖到另一个驱动器(或另一台机器)的文件夹程序的运行不会出现任何问题本文的启动器假定JRE总是在应用软件所在目录的一个子目录下也就是说JRE应当随同应用软件一起发布这样做的好处是使得应用软件完全不依赖于用户的环境确保了JRE与应用程序的兼容姓即使用户系统中原来已经有JRE增加一个额外的JRE也只不过稍微占用了一点磁盘空间但却能有效地保证应用软件的稳定姓
在某些场合你可能需要将一些配置参数移出程序例如放入一个配置文件特别是在需要频繁改动启动方式的开发阶段建议移出程序之外的配置选项包括启动类类的路径某些VM参数例如verbose