Java多次启动相同jar程序

背景

现在很多软件都支持集群部署,但是测试环境通常资源有限,所以一般通过单台机器模拟集群部署(使用不同端口,运行相同jar包),本文的目的就是通过多种方式实现此需求。

两个程序

1、jar程序

  ① springboot程序

  ② 只包含一个main方法,用于启动程序,输出进程ID

  ③ 路径:C:/demo.jar(windows) /demo.jar(Linux)

2、启动程序

  ① 包含main方法的程序

多种方式

1、通过URLClassLoader加载jar程序(windows平台)

2、通过java -jar命令启动jar程序(windows平台)

3、通过复制原始jar文件,启动不同的jar程序(windows平台)

4、通过Linux Shell脚本启动(Linux平台)

方式一

1、通过URLClassLoader加载jar程序(windows平台)

  ① 说明

    1) 启动程序多次加载jar程序

    2) jar程序和启动程序使用相同进程,非独立进程,无实际意义,仅介绍

  ② 启动jar程序:运行启动程序main方法

  ③ 终止jar程序:停止启动程序(因为共用同一个进程,终止主程序,jar程序会同时终止)

2、代码

  ① jar程序

@SpringBootApplication

public class DemoStarter {

    public static void main(String[] args) {

        // 获取进程Id

        String name = ManagementFactory.getRuntimeMXBean().getName();

        String processId = name.split("@")[0];

        System.out.println(processId);

        SpringApplication.run(DemoStarter.class, args);
    }
}

  ② 启动程序

import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class Starter1 {

    public static void main(String[] args) throws Exception {

        start("7001");
        start("7002");
        start("7003");
    }

    private static void start(String port) throws Exception {

        String path = "file:" + "C:/demo.jar";

        URLClassLoader classLoader = new URLClassLoader(new URL[]{new URL(path)});

        // jar程序的启动类完整路径
        Class demo = classLoader.loadClass("DemoStarter");

        Method method = demo.getMethod("main", String[].class);

        method.invoke(null, (Object) new String[]{port});
    }
}

方式二

1、通过java -jar命令启动jar包(windows平台)

  ① 说明

    1) 启动程序使用命令多次启动jar包

    2) 动态构建cmd命令(不同参数),启动相同jar程序,各个jar程序使用不同进程

  ② 启动jar程序

    1) 运行启动程序main方法

    2) 保存各个进程ID到文件

  ③ 终止jar程序

    1) 根据保存的进程ID停止各个jar程序

2、代码

  ① jar程序(同方式一)

  ② 启动程序

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Starter2 {

    public static void main(String[] args) throws Exception {

        cmd("7001");
        cmd("7002");
        cmd("7003");

        // 根据文件中的进程Id终止程序
        killByProcessId("PID1");
        killByProcessId("PID2");
        killByProcessId("PID3");
    }

    private static void cmd(String port) throws Exception {

        String cmd = "java -jar -Dserver.port=" + port + " " + "C:/demo.jar";

        Process p = Runtime.getRuntime().exec(cmd);
        InputStream is = p.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));

        // 获取进程Id(DemoStarter-->main方法
        // reader.readLine()第一行为System.out.println(processId)输出内容
        String processId;
        while ((processId = reader.readLine()) != null) {
            break;
        }
        is.close();
        reader.close();

        // 这里可以将进程ID保存到文件中
        System.out.println("processId:" + processId);
    }

    private static void killByProcessId(String processId) throws Exception {

        String cmd = "taskkill /F /PID \"" + processId + "\"";
        Runtime.getRuntime().exec(cmd);
    }
}

方式三

1、通过复制原始jar文件,启动不同的jar程序(windows平台)

  ① 说明

    1) 复制原始jar包,生成新的jar包

    2) 动态构建cmd命令(不同参数、不同jar包名称),启动不同jar包,各个jar包使用不同进程

  ② 启动jar程序

    1) 运行启动程序的main方法

    2) 保存各个进程ID到文件

  ③ 终止程序

    1) 根据保存的进程ID停止各个jar程序

  ④ 复制jar文件需要时间,但可以解决启动相同jar包可能存在的问题

2、代码

  ③ jar程序(同方式一)

  ④ 启动程序

import org.apache.commons.io.FileUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;

public class Starter3 {

    public static void main(String[] args) throws Exception {

        copyCmd();

        // 根据文件中的进程Id终止程序
        killByProcessId("PID1");
        killByProcessId("PID2");
        killByProcessId("PID3");
    }

    private static void copyCmd() throws Exception {

        File srcFile = new File("C:/demo.jar");
        File destiFile2 = new File("C:/demo2.jar");
        File destiFile3 = new File("C:/demo3.jar");

        // 删除之前复制的jar包
        FileUtils.forceDelete(destiFile2);
        FileUtils.forceDelete(destiFile3);

        FileUtils.copyFile(srcFile, destiFile2);
        FileUtils.copyFile(srcFile, destiFile3);

        copy("java -jar -Dserver.port=7001 C:/demo.jar");
        copy("java -jar -Dserver.port=7002 C:/demo2.jar");
        copy("java -jar -Dserver.port=7003 C:/demo3.jar");
    }

    private static void copy(String cmd) throws Exception {

        Process p;

        p = Runtime.getRuntime().exec(cmd);
        InputStream is = p.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));

        // 获取进程Id(DemoStarter-->main方法
        // reader.readLine()第一行为System.out.println(processId)输出内容
        String processId;
        while ((processId = reader.readLine()) != null) {
            break;
        }
        is.close();
        reader.close();

        // 这里可以将进程ID保存到文件中
        System.out.println("ProcessId:" + processId);
    }

    private static void killByProcessId(String processId) throws Exception {

        String cmd = "taskkill /F /PID \"" + processId + "\"";
        Runtime.getRuntime().exec(cmd);
    }
}

方式四

1、通过Linux Shell脚本启动(Linux平台)

  ① 执行java -jar命令

  ② 根据端口获取进程ID

  ③ 根据进程ID终止程序

2、代码

  ① jar程序(同方式一)

  ② Shell命令

    1) 启动程序

#!/bin/bash

java -jar -Dserver.port=7001 /demo.jar
java -jar -Dserver.port=7002 /demo.jar
java -jar -Dserver.port=7003 /demo.jar

  2) 终止程序

#!/bin/bash

pid1=`netstat -anp | grep 7001 | awk ‘{printf $7}‘ | cut -d/ -f1`
pid2=`netstat -anp | grep 7002 | awk ‘{printf $7}‘ | cut -d/ -f1`
pid3=`netstat -anp | grep 7003 | awk ‘{printf $7}‘ | cut -d/ -f1`

kill ${pid1}
kill ${pid2}
kill ${pid3}

问题&总结

  1、方式一可以通过调用method.invoke传递参数

  2、其它方式可通过jar命令传递参数

  3、启动程序通过Process启动jar程序并获取jar程序进程ID

  4、多次启动jar程序时报错:”unable to register MBean” 
      设置参数spring.jmx.enabled=false

  5、根据端口号获取进程ID(windows)
    netstat -ano|findstr "7001 7002 7003"

  6、根据进程ID停止进程(windows)

    taskkill /F /PID "1"

参考资料

  1、https://my.oschina.net/u/2971292/blog/2960777

  2、https://www.jianshu.com/p/3eea5e7e1e6f

  3、https://www.cnblogs.com/sxdcgaq8080/p/10579073.html

原文地址:https://www.cnblogs.com/gossip/p/11680024.html

时间: 2024-11-12 04:18:38

Java多次启动相同jar程序的相关文章

Java下如何启动windows 的程序

Java的java.lang.Runtime类提供了运行 Windows下cmd环境的方法exec(String command),所有在Windows cmd命令窗口下执行的程序,都能利用这个方法执行. 下边提供两个封装后的代码,一个是查看程序是否在运行,另一个是启动程序: 1.查看程序是否在运行:其中tasklist /FI "IMAGENAME eq processName.exe"是在Windows CMD命令下执行的命令 /** * 判断某个进程是否在运行中 * @param

shell脚本批量/单独启动、停止、重启java独立jar程序

本人最近半年使用阿里dubbo做开发,并在公司内部大力进行推广,将原来一个笨重且不易于维护的大项目切分成多个相对独立的java程序,好处是显而易见的,但是随着切分的独立运行程序包越来越多,程序的部署变成了一件非常头痛的问题,无耐之下,本人想到可否写一个shell脚本来批量/单独启动.停止.重启这些独立的java程序,之前没有写过shell脚本,研究二天后,终于将这个脚本写出来了,以后部署起来方便多了,废话不多说,直接贴上shell脚本,有需要的朋友可以根据自己项目修改前面的程序代码数组.程序名称

linux_后台启动多个java -jar 程序,及关闭

启动脚本 startup.sh #!/bin/bash x=$(($1)) while (($x>0)) do java -jar /home/chenpenghui/crawler/crawler-hb/StartUpIp.jar & sleep 3 x=$(($x-1)) done 线程数 等于 输入值 启动如下 ./startup.sh 10 停止脚本 clean.sh #!/bin/bash kill -9 `ps ax|grep /home/chenpenghui/crawler/

java获取cmd启动的程序的PID

笔记整理: 1 /*java获取cmd启动程序的PID */ 2 /*zzq581573832013-05-08上传*/ 3 //代码: 4 static interface Kernel32 extends Library{ 5 public static Kernel32 INSTANCE=(Kernel32) 6 Native.loadLibrary("kernel32", Kernel32.class); 7 public int GetProcessId(Long hProc

Java中动态加载jar文件和class文件

概述 诸如tomcat这样的服务器,在启动的时候会加载应用程序中lib目录下的jar文件以及classes目录下的class文件,另外像spring这类框架,也可以根据指定的路径扫描并加载指定的类文件,这个技术可以实现一个容器,容纳各类不同的子应用. Java类由于需要加载和编译字节码,动态加载class文件较为麻烦,不像C加载动态链接库只要一个文件名就可以搞定,但JDK仍提供了一整套方法来动态加载jar文件和class文件. 动态加载jar文件 // 系统类库路径 File libPath =

Java项目生成可执行jar包、exe文件以及在Windows下的安装文件

1.如何通过eclipse将Java项目生成可执行jar包 首先把在eclipse下的java项目导出jar file 下一步 下一步 下一步 最后点击完成,便生成了可执行的jar文件.可以在刚刚选择导出目录的文件夹中找到. 2.将刚刚生成的jar文件导出可执行的.exe文件,首先安装exe4j软件,下载地址如下:http://www.jb51.net/softs/541579.html,下载后安装破解.打开界面如下 直接下一步,选择第二个 下一步 下一步 如果要在64位下运行,则要点击下面那个

交通银行 Java Socket 服务启动 管理 WINDOWS 版

按照交通银行提供的无界面启动方法试验了很多次,都没有成功,所以自己动手用C# 知识写了一个. 小工具可以判断 交通银行 JAVA SOCKET 服务是否启动,并可以启动/关闭服务 主要代码如下: 判断服务是否启动 引用 :using System.Management; SelectQuery selectQuery = new SelectQuery(“select * from Win32_Process where Name = ‘java.exe’”); object cmdLine =

[Java]Hibernate所需要的jar包和作用释义

hibernate 需要的jar包 1)hibernate3.jar: Hibernate的核心库,没有什么可说的,必须使用的jar包 2)cglib-asm.jar: CGLIB库,Hibernate用它来实现PO字节码的动态生成,非常核心的库,必须使用的jar包 3)dom4j.jar: dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的特点,同时它也是一个开放源代  

Win7/Win8下双击运行jar程序的方法

问题 老妈喜欢看小说,又不会下载,于是用Java写了个自动下载小说的小程序 我用的Swing UI,直接生成了.jar文件,双击即可运行 很诡异的是,用Eclipse直接run可以运行,但是Export出jar文件以后双击却没有反应 探究 怀疑是不是Eclipse的导出功能坏掉了,于是用了flatjar等工具重新打包,仍然不行 走了很多弯路以后终于Google到了问题的所在: win7/win8的jar文件默认关联的程序是java.exe而不是javaw.exe 在右键 -> 打开方式里面这两个