服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

打造个性化java启动器


  主要内容:
  
  ________________________
  
   一、java程序的启动过程
  
   二、windows平台的启动器
  
   三、配置和使用
  
  ________________________
  
  对于普通用户来说,java最让人不习惯的是程序的启动过程;即使对于富有经验的开发者,为了用默认的装载器启动java程序,不得不编写大量批命令、脚本文件,不得不在命令行环境下进行大量的复制/粘贴操作,也很容易出现误操作。
  
  用惯了windows方便快捷的gui,人们早就习惯了通过双击运行程序的方式。对于java程序,要实现这个本机启动功能就必须编写定制的启动器。用定制启动器启动java程序不仅方便了最终用户,而且使软件作品看起来更专业。本文就以windows平台为例,介绍如何构造java定制启动器。
  打造个性化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) &

扫描关注微信公众号