Windows系统服务(NT服务)相对于普通应用程序最直接的一个优点是系统启动后就可直接运行而无需用户登录系统。事实上,作为服务器来使用的系统,通常也并不需要登录系统,这样不只是方便,也提升了系统的安全性。不过,通常情况下,Windows系统服务使用CC++实现,而有些时候基于某些因素的考虑,我们期望使用Java来实现系统服务,可以借助开源的JavaService达到此目的。

以下演示其实现过程。

首先编写实现NT服务的Java类,以下的示例代码通过两个类来达到实现NT服务的目的。类TestService提供了NT服务启动及停止的控制方法,而类Service则实现了NT服务真正要完成的工作。类TestService及类Service的完整代码如下:

TestService中的方法StartService用于启动NT服务,而StopService方法则用于停止NT服务。从代码中可以看出方法StartServiceStopService实际上是分别实现了启动线程与终止线程的功能,而这里的线程就是实现NT服务的线程。这里有两点要特别注意:

1. 方法StartServiceStopService都拥有参数String[] args,在安装NT服务时,可以指定启动或停止服务的参数,这些指定的参数将可以通过String[] args传递给方法StartServiceStopService。在本例中由于演示的功能较为简单,故而未曾使到该参数。

2. StartService方法中启动线程之前,有必要将线程设定为用户线程。其原因在于如果线程是一个后台线程,则当主程序结束后,JVM会自动退出,后台线程当然也就终止执行,而如果主程序结束时,还有用户线程在运行,则JVM不会自动退出,而是要等用户线程结束后才退出。因此,要保证NT服务正常运行,这一点也是要特别注意的。

Service是实现NT服务的线程类,NT服务要完成的功能在方法run中完成,在示例中它仅仅输出了当前时间,在实际应用中应根据需要在其中完成更为复杂的功能。方法setRunFlaggetRunFlag分别用于设定线程是否运行的标志和取得该标志值。setRunFlag方法需要在类外被调用并通过设定不同的参数通知线程是否需要继续执行;getRunFlag方法则取得该标志,它只在方法run的循环中被调用,所以声明为私有方法。此外,由于在不同线程中对线程运行标志进行设定与读取,所以方法setRunFlaggetRunFlag被设定为同步方法。

代码编写完成后,执行编译过程,必要时还可以打包成jar文件。

随后的工作就是利用JavaService注册NT服务,JavaService是一个开源项目,其项目地址为http://javaservice.objectweb.org,打开该地址后下载JavaService压缩包,并将解压之后的JavaService.exe置于上述代码编译之后包所在的目录,或者将JavaService.exe所在目录添加到环境变量PATH之中。

JavaService一共提供了8个参数可供选择,其中我们只需要关心安装NT服务的-install参数和卸载NT服务的-uninstall参数。

使用-install参数安装NT服务时还需要提供与服务相关的其它一些参数,其命令格式如下:

JavaService -install service_name jvm_library [jvm_options]

-start start_class [-method start_method] [-params (start_parameters)]

[-stop start_class [-method stop_method] [-params (stop_parameters)]]

[-out out_log_file] [-err err_log_file]

[-current current_dir]

[-path extra_path]

[-depends other_service]

[-auto | -manual]

[-shutdown seconds]

[-user user_name -password password]

[-append | -overwrite]

[-startup seconds]

[-description service_desc]

相关参数的作用说明如下:

service_name: The name of the service.

jvm_library: The location of the JVM DLL used to run the service.

jvm_option: An option to use when starting the JVM, such as:

"-Djava.class.path=c:/classes" or "-Xmx128m".

start_class: The class to load when starting the service.

start_method: The method to call in the start_class. default: main

start_parameters:Parameter(s) to pass in to the start_method.

stop_class: The class to load when stopping the service.

stop_method: The method to call in the stop_class. default: main

stop_parameters: Parameter(s) to pass in to the stop_method.

out_log_file: A file to redirect System.out into. (gets overwritten)

err_log_file: A file to redirect System.err into. (gets overwritten)

current_dir: The current working directory for the service.

Relative paths will be relative to this directory.

extra_path: Path additions, for native DLLs etc. (no spaces)

other_service: Single service name dependency, must start first.

auto / manual: Startup automatic (default) or manual mode.

seconds: Java method processing time (startup:sleep, shutdown:timeout).

user_name: User specified to execute the service (user@domain).

password: Password applicable if user specified to run the service.

append / overwrite: Log file output mode, append (default) or overwrite.

service_desc: Text describing installed service (quoted string, max 1024).

要安装前面我们用Java编写的NT服务,可以用以下命令完成:

JavaService.exe -install TJS "%JAVA_HOME%/jre/bin/server/jvm.dll" -Xmx128m -Djava.class.path=%CLASSPATH% -start com.yanzhijun.TestService -method StartService -stop com.yanzhijun.TestService -method StopService -out "%CD%/out.log" -err "%CD%/err.log" -current "%CD%" –auto

上述命令中用“%”包含的是环境变量,其中JAVA_HOMEJDK的安装目录,CLASSPATH是为类的查找路径,这两者与正常配置JDK保持一致即可。CD则是当前目录。

成功安装服务以后,可以用以下命令启动服务:

net start TJS

由于在安装服务时指定了auto参数,所以服务被设定为自动启动,因此机器重启后无需使用上述命令这个NT服务就会启动。

如果需要停止服务,可以使用下列命令:

net stop TJS

这样就可以正常地使用Java所编写的NT服务了,如果不需要该服务,则应将该服务卸载,卸载服务的命令相比安装要简单地多,其格式如下:

JavaService -uninstall service_name

例如要卸载刚才安装的名称为TJS的服务,可以执行以下命令:

JavaService -uninstall TJS

注意Java代码所生成的NT服务类所存储的目录路径中不能包含中文,否则启动服务时会失败。

欢迎访问梦断酒醒的博客http://www.yanzhijun.com

更多相关文章

  1. Java Executor多线程框架
  2. “不是抽象的,也不重写抽象的方法”错误
  3. Android高手进阶教程(二十)之---Android与JavaScript方法相互调
  4. java线程--volatile实现可见性
  5. 手低眼高 初学者学习Hibernate的方法
  6. Java常用类及其常用方法
  7. 本地方法中printf如何传给java--java系统级命名管道
  8. Maven:主线程中的NoClassDefFoundError
  9. java线程池使用场景和使用方法较详细文摘

随机推荐

  1. 解决PHP中Web程序中shell_exec()执行Shel
  2. PHP如何下载远程文件到指定目录
  3. PHP执行Linux命令的两个有用的函数exec和
  4. php中关于isset()、isnull()和empty()的
  5. php实现利用expat方式解析xml文件
  6. curl提交json数据的方法
  7. 超简单的Mac下搭建PHP环境教程
  8. 利用webhook使php项目自动部署
  9. PHP生命周期及fpm的运作方式
  10. 详解PHP的self关键字