|
在实际工作中,java开发的springboot等通过jar包部署需要一直运行的程序部署到服务器上时,都希望后台运行,方便管理程序服务、防止被误操作关闭,本文结合自己工作经验讲解jar包后台运行的两种方式,分别是按操作系统支持的特殊方式和统一执行命令的方式。方式一:按操作系统支持的方式后台运行可执行jar包程序可以按操作系统支持的方式运行,不同操作系统执行命令和方式不一样,这里主要讲解linux操作系统和window操作系统下如何按操作系统支持的特殊方式后台运行。linux操作系统Linux操作系统java程序后台运行又主要分如下两种方式:1.通过nohup命令和&符号运行。终端关闭后程序也会继续运行,示例如下:nohupjava-jardemo.jar>nohup.log2>&1&示例命令说明:nohup:使得终端关闭,运行的命令也不中断。java-jardemo.jar:用于启动jar包。nohup.log:标准输出重定向到nohup.log文件。2>&1:标准错误重定向到标准输出(即nohup.log文件)。&:命令放入后台执行。执行上述命令后,程序后台运行,日志记录到nohup.log里,可以使用tail等命令看日志文件,并且会得到一个进程ID(PID,这个PID可以通过psax|grep"demo.jar"查找),可以使用kill命令通过这个PID来终止进程。2.jar配置为可自启动的服务。在Linux上将jar文件设置为服务需要编写一个系统服务单元文件(.service文件),然后使用systemd来管理服务。以下是一个示例:创建服务单元文件 /etc/systemd/system/your-service.service:[Unit]Description=YourJavaApplicationasaServiceAfter=network.target[Service]User=Type=simpleExecStart=/usr/bin/java-jar/path/to/your-application.jarRestart=on-failure[Install]WantedBy=multi-user.target重新加载systemd管理器配置:sudosystemctldaemon-reload启动服务:sudosystemctlstartyour-service.service设置服务开机自启:sudosystemctlenableyour-service.service确保替换 和 /path/to/your-application.jar 为实际的用户名和jar文件路径。如果需要传递额外的Java选项,可以在 ExecStart 中添加。请注意,这个示例假定你已经有权限执行systemctl命令,并且你的系统已经安装了Java运行时环境(JRE)或JavaDevelopmentKit(JDK)。如果没有安装Java,你需要先安装它,通常可以使用系统的包管理器,例如在Ubuntu上使用 sudoapt-getinstalldefault-jdk。window操作系统要在Windows环境下使jar包在后台运行,可以使用javaw命令代替java命令,javaw命令不会打开命令行窗口,适合运行没有图形界面但需要在后台运行的Java应用程序;也可以使用winsw工具安装为系统服务实现后台运行。结合操作系统支持的方式,window下java程序后台运行又主要分如下四种方式:1.使用javaw-jardemo.jar命令运行jar包打开命令提示符或PowerShell,使用javaw-jardemo.jar命令运行jar包。2.定时运行或开机自启如果需要定时运行或开机自启,可以创建一个批处理文件来运行jar包,可以通过Windows任务计划程序来设置。示例批处理文件(run-jar.bat)echooffstartjavaw-jardemo.jarexit3.通过VBS脚本运行如果你想要该进程在后台默默运行,可以创建VBS脚本来启动它:CreateObject("Wscript.Shell").Run"cmd/cstartjavaw-jaryour-application.jar",0,True保存为.vbs文件,例如run-jar.vbs,双击该文件即可在后台运行jar包。4.安装为服务方式运行将其作为服务安装,可以使用winsw工具来将你的Java应用程序包装成Windows服务。这样可以确保即使命令行关闭,程序也会继续运行。下载winsw的二进制文件,并重命名为你的服务名称,例如demo.exe。然后创建一个配置文件demo.xml,最后通过install安装为windows服务。安装服务的基本步骤如下:下载winsw二进制文件。重命名为demo.exe。创建demo.xml配置文件,指定jar路径和其他参数。运行demo.exeinstall来安装服务。这样,你的Java应用程序就会作为Windows服务在后台运行,并可以设置为开机启动。方式二:统一执行命令的方式(Runtime.getRuntime().exec())方式一虽然都能实现jar程序后台运行但是方式并不统一,不同操作系统需要按不同方式配置,java程序既然是跨平台的,为什么个不能让jar包后台运行的命令也统一呢?答案是肯定可以的,这儿要讲的就是这种方式,实现也比较简单,Vertx等项目就是按这种方式,通过java调用系统命令实现(Runtime.getRuntime().exec())。这种方式目标使用相同启动命令使得程序可以在不同操作系统上后台运行。实现思路(Springboot项目举例)程序启动main方法传入一个后台运行的标志参数,比如为start。main方法里获取args参数判断是否包含start参数,如果包含就获取启动命令和按操作系统设置其他启动参数,然后通过java调用系统命令方式(Runtime.getRuntime().exec())再次执行不包括start参数的启动命令。通过java调用系统命令方式(Runtime.getRuntime().exec())再次执行不包括start参数的启动命令后,又进入main方法,main方法args参数里没有start参数,就执行Springboot项目启动代码,这样就实现了程序后台运行。执行命令示例: java-jardemo.jarstart示例代码如下:packagecom.demo;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importjava.io.File;importjava.util.*;@SpringBootApplicationpublicclassDemoApplication{publicstaticfinalStringSTART="start";privatestaticStringosName=System.getProperty("os.name").toLowerCase();privatestaticStringid=UUID.randomUUID().toString();publicstaticvoidmain(String[]args){HashSetargSet=newHashSet(Arrays.asList(args));if(argSet.contains("-Dapplication.id")||!argSet.contains(START)){SpringApplication.run(DemoApplication.class,args);}else{start();}}/***参考io.vertx.core.impl.launcher.commands.StartCommand*/publicstaticvoidstart(){System.out.println("Startingapplicationbackground...");Listcmd=newArrayList()rocessBuilderbuilder=newProcessBuilder();addJavaCommand(cmd);//Addtheclasspathtoenv.builder.environment().put("CLASSPATH",System.getProperty("java.class.path"));//jar包运行if(getJar()!=null){cmd.add("-jar");cmd.add(getJar());}else{//开发工具运行cmd.add(getFirstSegmentOfCommand());cmd.add("run");}cmd.add("-Dapplication.id="+id);try{builder.command(cmd);builder.start();System.out.println(id);}catch(Exceptione){System.out.println("Cannotcreateapplicationprocess");System.exit(12);}}privatestaticvoidaddJavaCommand(Listcmd){if(osName.contains("windows")){cmd.add("cmd.exe");cmd.add("/C");cmd.add("start");cmd.add("application-id-"+id);cmd.add("/B");}cmd.add(getJava().getAbsolutePath());Stringopts=System.getenv("JAVA_OPTS");if(opts!=null){cmd.addAll(Arrays.asList(opts.split("")));}}privatestaticFilegetJava(){Filejava;Filehome=newFile(System.getProperty("java.home"));if(osName.contains("windows")){java=newFile(home,"bin/java.exe");}else{java=newFile(home,"bin/java");}if(!java.isFile()){System.out.println("Cannotfindjavaexecutable-"+java.getAbsolutePath()+"doesnotexist");System.exit(14);}returnjava;}publicstaticStringgetJar(){//Checkwhetherornotthe"sun.java.command"systempropertyisdefined,//ifitis,checkwhetherthefirstsegmentofthecommandendswith".jar".Stringsegment=getFirstSegmentOfCommand();if(segment!=null&segment.endsWith(".jar")){returnsegment;}else{//Secondattendistochecktheclasspath.Iftheclasspathcontainsonlyoneelement,//it'sthefatjarStringclasspath=System.getProperty("java.class.path");if(!classpath.isEmpty()&!classpath.contains(File.pathSeparator)&classpath.endsWith(".jar")){returnclasspath;}}returnnull;}/***@returnthefirstsegmentofthecommandline.*/publicstaticStringgetFirstSegmentOfCommand(){Stringcmd=System.getProperty("sun.java.command");if(cmd!=null){String[]segments=cmd.split("");if(segments.length>=1){returnsegments[0];}}returnnull;}}
|
|