Java屢次啓動相同jar程序

背景

如今不少軟件都支持集羣部署,可是測試環境一般資源有限,因此通常經過單臺機器模擬集羣部署(使用不一樣端口,運行相同jar包),本文的目的就是經過多種方式實現此需求。html

兩個程序

一、jar程序java

  ① springboot程序spring

  ② 只包含一個main方法,用於啓動程序,輸出進程IDapache

  ③ 路徑:C:/demo.jarwindows/demo.jarLinuxwindows

二、啓動程序springboot

  ① 包含main方法的程序bash

多種方式

一、經過URLClassLoader加載jar程序(windows平臺)測試

二、經過java -jar命令啓動jar程序(windows平臺)spa

三、經過複製原始jar文件,啓動不一樣的jar程序(windows平臺).net

四、經過Linux Shell腳本啓動(Linux平臺)

方式一

一、經過URLClassLoader加載jar程序(windows平臺)

  ① 說明

    1) 啓動程序屢次加載jar程序

    2) jar程序和啓動程序使用相同進程,非獨立進程,無實際意義,僅介紹

  ② 啓動jar程序:運行啓動程序main方法

  ③ 終止jar程序:中止啓動程序(由於共用同一個進程,終止主程序,jar程序會同時終止)

二、代碼

  ① 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});
    }
}

 

方式二

一、經過java -jar命令啓動jar包(windows平臺)

  ① 說明

    1) 啓動程序使用命令屢次啓動jar

    2) 動態構建cmd命令(不一樣參數),啓動相同jar程序,各個jar程序使用不一樣進程

  ② 啓動jar程序

    1) 運行啓動程序main方法

    2) 保存各個進程ID到文件

  ③ 終止jar程序

    1) 根據保存的進程ID中止各個jar程序

二、代碼

  ① 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);
    }
}

 

 

方式三

一、經過複製原始jar文件,啓動不一樣的jar程序(windows平臺)

  ① 說明

    1) 複製原始jar包,生成新的jar

    2) 動態構建cmd命令(不一樣參數、不一樣jar包名稱),啓動不一樣jar包,各個jar包使用不一樣進程

  ② 啓動jar程序

    1) 運行啓動程序的main方法

    2) 保存各個進程ID到文件

  ③ 終止程序

    1) 根據保存的進程ID中止各個jar程序

  ④ 複製jar文件須要時間,但能夠解決啓動相同jar包可能存在的問題

二、代碼

  ③ 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);
    }
}

 

方式四

一、經過Linux Shell腳本啓動(Linux平臺)

  ① 執行java -jar命令

  ② 根據端口獲取進程ID

  ③ 根據進程ID終止程序

二、代碼

  ① 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}

 

問題&總結

  一、方式一能夠經過調用method.invoke傳遞參數

  二、其它方式可經過jar命令傳遞參數

  三、啓動程序經過Process啓動jar程序並獲取jar程序進程ID

  四、屢次啓動jar程序時報錯:」unable to register MBean」 
      設置參數spring.jmx.enabled=false

  五、根據端口號獲取進程IDwindows
    netstat -ano|findstr "7001 7002 7003"

  六、根據進程ID中止進程(windows

    taskkill /F /PID "1"

 

參考資料

  一、http://www.javashuo.com/article/p-wzvcygmo-kt.html

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

  三、http://www.javashuo.com/article/p-vebdlevd-hg.html

相關文章
相關標籤/搜索