|
打造个性化Java启动器
发表日期:2008-1-5
|
主要内容: ________________________ 一、Java程序的启动过程 二、Windows平台的启动器 三、配置和使用 ________________________ 对于普通用户来说,Java最让人不习惯的是程序的启动过程;即使对于富有经验的开发者,为了用默认的装载器启动Java程序,不得不编写大量批命令、脚本文件,不得不在命令行环境下进行大量的复制/粘贴操作,也很轻易出现误操作。 用惯了Windows方便快捷的GUI,人们早就习惯了通过双击运行程序的方式。对于Java程序,要实现这个本机启动功能就必须编写定制的启动器。用定制启动器启动Java程序不仅方便了最终用户,而且使软件作品看起来更专业。本文就以Windows平台为例,介绍如何构造Java定制启动器。 Java程序可以由任何本机运行的程序调用执行。所谓Java启动器,就是一个专门用来启动Java程序的本机执行程序。最常见的启动器是Sun在Java Runtime Environment的/bin目录中提供的启动器,就Windows平台而言,它们是java.exe和javaw.exe。前者运行时打开两个窗口:一个是接收System.out/err和启动器输出的控制台窗口,另一个是Java程序本身的窗口;javaw运行时不打开控制台窗口。在J2SE/EE平台中,虚拟机以动态库的形式实现,也放在/bin目录下。动态库的名字在Windows中是java.dll,在Unix中是java.so。所谓“装入虚拟机”,就是指装入这个动态库。 提供给VM的参数可以通过两种方式指定,或者是在启动器的命令行参数中指定,或者通过定义相应的环境变量指定。只有一个参数例外——要启动的类的名称只能在启动器的命令行参数中指定。虽然指定方式的多样姓为人们各取所需带来了方便,但不可否认地,它也正是许多混乱的根源。使用定制启动器能够完全避免这方面的问题。 当VM结束启动类的main()方法的运行,启动器调用destroy()方法释放各种资源并退出。应当注重的是,VM一旦开始运行,我们就不能再卸载它。对于Java启动器来说,能否关闭VM无关紧要,因为启动器会随着Java程序的退出而退出;然而,对于嵌入了VM的本机应用,例如浏览器,这意味着有一块内存被永久姓地占用,不能再收回。 二、Windows平台的启动器 搞清楚了Java程序的启动过程,我们就可以开始编写启动器的代码。下面这个启动器用C++写成,适合于所有Windows平台。 // Windows平台下的Java程序启动器 // 适用于1.2或更高版本的VM #include #include #include using namespace std; void vShowError(string sErrorMessage); void vShowLastError(string sErrorMessage); void vDestroyVM(JNIEnv *env, JavaVM *jvm); void vAddOption(string& sName); JavaVMOption* vm_options; int mctOptions = 0; int mctOptionCapacity = 0; boolean GetApplicationHome(char *buf, jint sz); typedef jint (CALLBACK *CreateJavaVM)(JavaVM **pvm, JNIEnv **penv, void *args); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){ JNIEnv *env; JavaVM *jvm; jint jintVMStartupReturnValue; jclass jclassStartup; jmethodID midStartup; // 确定各种文件所在的路径 // -应用的主目录 char home[2000]; if (!GetApplicationHome(home, sizeof(home))) { vShowError("不能确定应用的主目录。"); return 0; } string sAppHome(home); string sOption_AppHome = "-Dapplication.home=" + sAppHome; string sJREPath = sAppHome + "\jre"; // -VM路径 string sRuntimePath = sJREPath + "\bin\classic\"; string sJVMpath = sRuntimePath + "jvm.dll"; // -启动路径 string sBootPath = sJREPath + "\lib"; string sOption_BootPath = "-Dsun.boot.class.path=" + sBootPath; // -CLASSPATH string sClassPath = sAppHome + "\classes"; string sOption_ClassPath = "-Djava.class.path=" + sClassPath; // 设置VM参数 // vAddOption(string("-verbose")); vAddOption(sOption_ClassPath); vAddOption(sOption_AppHome); // VM初始化参数 JavaVMInitArgs vm_args; vm_args.version = 0x00010002; vm_args.options = vm_options; vm_args.nOptions = mctOptions; vm_args.ignoreUnrecognized = JNI_TRUE; // 装入JVM库 HINSTANCE hJVM = LoadLibrary(sJVMpath.c_str()); if( hJVM == NULL ){ vShowLastError("不能从下面的路径装入JVM:" + sJVMpath); return 0; } // 启动1.2/3/4 VM CreateJavaVM lpfnCreateJavaVM = (CreateJavaVM) GetProcAddress(hJVM, "JNI_CreateJavaVM"); jintVMStartupReturnValue = (*lpfnCreateJavaVM) (&jvm, &env, &vm_args); // 是否成功? if (jintVMStartupReturnValue FindClass(sStartupClass.c_str()); if (jclassStartup == NULL) { string sErrorMessage ="找不到启动类[" +sStartupClass + "]"; vShowError(sErrorMessage); vDestroyVM(env, jvm); return 0; } // 要启动的方法 string sStartupMethod_Identifier = "main"; string sStartupMethod_TypeDescriptor ="([Ljava/lang/String;)V"; midStartup = env->GetStaticMethodID(jclassStartup, sStartupMethod_Identifier.c_str(), sStartupMethod_TypeDescriptor.c_str()); if (midStartup == NULL) { string sErrorMessage = "找不到启动方法["+ sStartupClass + "."+ sStartupMethod_Identifier + "],类型描述符是[" + sStartupMethod_TypeDescriptor + "]"; vShowError(sErrorMessage); vDestroyVM(env, jvm); return 0; } // 构造启动方法的参数 jstring jstringExampleArg; jclass jclassString; jobjectArray jobjectArray_args; jstringExampleArg = env->NewStringUTF("string1"); if (jstringExampleArg == NULL){ vDestroyVM(env, jvm); return 0; } jclassString = env->FindClass("java/lang/String"); jobjectArray_args = env->NewObjectArray(1, jclassString, jstringExampleArg); if (jobjectArray_args == NULL){ vDestroyVM(env, jvm); return 0; } // 调用启动方法启动Java程序 env->CallStaticVoidMethod(jclassStartup, midStartup, jobjectArray_args); // 在退出之前尝试分离主线程 if (jvm->DetachCurrentThread() != 0) { vShowError("分离主线程失败。\n"); } // 只要还有非守护线程,下面的调用将一直被挂起 jvm->DestroyJavaVM(); return 0; } void vDestroyVM(JNIEnv *env, JavaVM *jvm){ if (env->ExceptionOccurred()) { env->ExceptionDescribe(); } jvm->DestroyJavaVM(); } void vShowError(string sError) { MessageBox(NULL, sError.c_str(), "错误", MB_OK); } /* 在对话框中显示错误信息,括号内包含 的GetLastError错误信息 */ void vShowLastError(string sLocalError) { LPVOID lpSystemMsgBuf; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER FORMAT_MESSAGE_FROM_SYSTEM FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &
|
|
上一篇:动态Proxy与Java ACL用户访问控制机制实现
人气:634
下一篇:Java:并发使一切变得简单
人气:698 |
浏览全部Java的内容
Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐
|
|