将java程序安装成系统服务_将Java程序制作成windows系统服务相关

用EXE4J将Java程序制作成windows系统服务。具体方法略。

通常情况下,这样做是没有问题的。

但是如果java程序中有调用DLL文件的内容时,EXE4J生成的系统服务就无法正常运行。跟踪的结果是程序卡在调用DLL方法的代码上(用JNative调用DLL)。

同样的情况也出现在使用jeasyopc时,怀疑也是同样的原因,因为使用jeasyopc.jar时,会在当前文件夹下生成一个JCustomOpc.dll的文件。

出现问题的当时,没有找到解决方法,只能放弃将Java程序做成系统服务,而是将该程序做成tomcat自启动项目,用tomcat来代替想要做成的系统服务。

这样处置会有很多隐患。

现在,又找到了另一个替代方案。

用处理OPC Client的Java程序来举例:

首先假设OPC Client的程序已经开发完成,简称为OPC程序。

做一个定时任务,检查系统中OPC程序是否运行,如果没有运行,就启动OPC程序。

将定时任务做成系统服务。这样可以避免在在服务中直接调用DLL。简称为定时任务服务。

完成这个思路,有2个问题需要处理:

首先,启动OPC程序:

这个问题很简单,代码如下

new Thread() {

public void run() {

try {

Runtime.getRuntime().exec(cmd);

} catch (final SecurityException ex) {

ex.printStackTrace();

} catch (final IOException ex) {

ex.printStackTrace();

}

}

}.start();

这段代码中cmd变量就是OPC程序的启动命令,大概就是Java -cp “.\lib\log4j-1.2.15.jar;” opc.OPC,需要注意的就是路径问题。

其次就是检查系统中OPC程序是否运行:

这个问题有2种处理方式:

一是OPC程序开一个任意监听端口,而定时任务服务将试图连接这个端口与OPC程序通讯,只要定时任务服务能顺利与OPC程序通讯,就说明OPC程序已经在运行了。具体实现略。

没有采用这样方法的原因是因为OPC程序和定时任务程序紧耦合了。

二是使用JDK中提供tools.jar中的工具。

import sun.jvmstat.monitor.*;

import sun.management.ConnectorAddressLink;

import java.io.File;

import java.util.HashMap;

import java.util.Map;

import java.util.Set;

public class LocalVirtualMachine {

private String address;

private String commandLine;

private String displayName;

private int vmid;

private boolean isAttachSupported;

private String jvmArgs;

public LocalVirtualMachine(int vmid, String commandLine, String jvmArgs, boolean canAttach, String connectorAddress) {

this.vmid = vmid;

this.commandLine = commandLine;

this.jvmArgs = jvmArgs;

this.address = connectorAddress;

this.isAttachSupported = canAttach;

this.displayName = getDisplayName(commandLine);

}

public String getAddress() {

return address;

}

public String getCommandLine() {

return commandLine;

}

public String getDisplayName() {

return displayName;

}

public boolean isAttachSupported() {

return isAttachSupported;

}

public String getJvmArgs() {

return jvmArgs;

}

public int getVmid() {

return vmid;

}

private static String getDisplayName(String commandLine) {

// trim the pathname of jar file if it's a jar

String[] res = commandLine.split(" ", 2);

if (res[0].endsWith(".jar")) {

File jarfile = new File(res[0]);

String displayName = jarfile.getName();

if (res.length == 2) {

displayName += " " + res[1];

}

return displayName;

}

return commandLine;

}

public static Map getMonitoredVMs() {

Map map = new HashMap();

MonitoredHost host;

Set vms;

try {

host = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null));

vms = host.activeVms();

} catch (java.net.URISyntaxException sx) {

throw new InternalError(sx.getMessage());

} catch (MonitorException mx) {

throw new InternalError(mx.getMessage());

}

// LocalMonitoredVm

for (Object vmid : vms) {

if (vmid instanceof Integer) {

int pid = (Integer) vmid;

String name = vmid.toString(); // default to pid if name not available

boolean attachable = false;

String address = null;

String jvmArgs = null;

try {

MonitoredVm mvm = host.getMonitoredVm(new VmIdentifier(name));

// use the command line as the display name

name = MonitoredVmUtil.commandLine(mvm);

jvmArgs = MonitoredVmUtil.jvmArgs(mvm);

attachable = MonitoredVmUtil.isAttachable(mvm);

address = ConnectorAddressLink.importFrom(pid);

mvm.detach();

} catch (Exception x) {

// ignore

}

map.put((Integer) vmid,

new LocalVirtualMachine(pid, name, jvmArgs, attachable, address));

}

}

return map;

}

}

通过遍历getMonitoredVMs()方法的Map中的localVirtualMachine.getDisplayName(),就可以得到当前操作系统中由java启动的所有程序的名称。

好吧,我承认这段代码是抄袭Jconsole的源代码。

综合以上:

final String[] aArray = cmd.split(" ");

if (aArray.length > 0) {

Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new Runnable() {

public void run() {

boolean isRunning = false;

Map map = LocalVirtualMachine.getMonitoredVMs();

for (LocalVirtualMachine localVirtualMachine : map.values()) {

if (localVirtualMachine.getDisplayName().equals(aArray[aArray.length-1])) {

isRunning = true;

break;

}

}

map.clear();

if (!isRunning) {

new Thread() {

public void run() {

try {

Runtime.getRuntime().exec(cmd);

} catch (final SecurityException ex) {

ex.printStackTrace();

} catch (final IOException ex) {

ex.printStackTrace();

}

}

}.start();

}

}

}, 0, 5, TimeUnit.SECONDS);

}

}

这样做的好处是解除了OPC程序和定时任务服务直接的耦合。

不可否认的是,以上方法依然是治标不治本的方法。到现在为止,还是没有解决EXE4J生成的系统服务中无法调用DLL的问题。甚至问题的根源是不是因为调用了DLL,都不是很有把握。希望达人指点,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值