背景

现在很多软件都支持集群部署,但是测试环境通常资源有限,所以一般通过单台机器模拟集群部署(使用不同端口,运行相同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

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

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

    本人最近半年使用阿里dubbo做开发,并在公司内部大力进行推广,将原来一个笨重且不易于维护的大项目切分成多个相对独立的java程序,好处是显而易见的,但是随着切分的独立运行程序包越来越多,程序的部署变 ...

  2. Java命令行启动jar包更改默认端口以及配置文件的几种方式

    Java命令行启动jar包更改默认端口以及配置文件的几种方式 java -jar xxx.jar --server.port=8081 默认如果jar包没有启动文件,可以采用这种方式进行启动 java ...

  3. 使用 Java Service Wrapper 启动java后台进程服务

    Java Service Wrapper (http://wrapper.tanukisoftware.com/doc/english/product-overview.html)可以很方便得在各个平 ...

  4. 手把手教你如何把java代码,打包成jar文件以及转换为exe可执行文件

    1.背景: 学习java时,教材中关于如题问题,只有一小节说明,而且要自己写麻烦的配置文件,最终结果却只能转换为jar文件.实在是心有不爽.此篇博客教你如何方便快捷地把java代码,打包成jar文件以 ...

  5. Java之Property-统获取一个应用程序运行的次数

    package FileDemo; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStre ...

  6. java classpath import package 机制 @Java的ClassPath, Package和Jar

    java classpath import package 机制   從一個簡單的例子談談package與import機制 基本原則:為什麼需要將Java文件和類文件切實安置到其所歸屬之Package ...

  7. Intellij IDEA下导出Java工程的可运行JAR包

    Intellij IDEA下导出Java工程的可运行JAR包 昨天一直向导出一个Java工程的可运行JAR包,然后查阅网上的资料以及自己一遍一遍的尝试,均以失败告终.可以导出JAR包,但是导出的JAR ...

  8. Jar程序使用MyBatis集成阿里巴巴druid连接池

    在写jar程序,而不是web程序的时候,使用mybatis作为持久层,可以集成POOLED连接池,而阿里的druid不能用,确实很郁闷.不过有办法. 首先准备好数据库配置文件 然后对Druid进行一个 ...

  9. java.io.FileNotFoundException: ..\lib\commons-el.jar

    安装openfire成功后,启动遇到java.io.FileNotFoundException: ..\lib\commons-el.jar错误,并不是缺少了jar包,只需以管理员身份运行即可解决.

随机推荐

  1. 老大难的GC原理及调优,这下全说清楚了

    概述 本文介绍GC基础原理和理论,GC调优方法思路和方法,基于Hotspot jdk1.8,学习之后将了解如何对生产系统出现的GC问题进行排查解决 阅读时长约30分钟,内容主要如下: GC基础原理,涉 ...

  2. Idea中SpringBoot引入thymeleaf没有提示

    问题描述: 最近使用Idea搭建SpringBoot时,用到了 thymeleaf,但是出现了点问题:输入th: 代码有没有提示. 解决方法: <html lang="en" ...

  3. java String字符串编码类型转换

    /** * 前后端数据乱码问题 * 解决办法1: * 乱码原因:一编一解码型不一致导致. * [main description] * @param {[type]} String[] args [d ...

  4. Django 之restfromwork 源码分析以及使用之--视图组件

    restframework 源码分析以及使用 mixins 中的五种类方法 from rest_framework import mixins # mixins 中一种有五种类 # 第一种:用户保存数 ...

  5. centos7 升级最新版内核 并安装 bcc-tools

    centos7 升级最新版内核 升级系统 [root@jikeshijian ~]# yum update -y 安装 ELRepo [root@jikeshijian ~]# rpm --impor ...

  6. QT,QT/E,Qtopia,qt creator的联系与区别

    关于qt,qte,qtopia,qt creator它们之间的区别和联系,相信对所有刚刚入门qt的同学来说都是很模糊的.我在刚开始接触qt的时候也是这样,而且我第一次接触的是qte,因为要在arm上开 ...

  7. Linux(Redhat)传送门汇总

    Linux(Redhat)传送门汇总 linux 环境布置 常用命令与shell 常用命令 shell 环境布置 Linux虚拟机安装(rhel 7.4) 虚拟机网络设置 VMware虚拟机开机启动 ...

  8. 1.2 管理 NetBackup 许可证

    关于管理 NetBackup 许可证 NetBackup许可证密钥是在安装软件时添加的.对于需要单独购买的选件,可以稍 后在"许可证密钥"对话框中添加许可证. 注意:在进行任何许可 ...

  9. P1850 换教室[dp+期望]

    流下了不会概率的眼泪,由于不会概率,转移少写了点东西... 这个dp很简单,就是一个普通的线性dp加点期望.(刚开始写这道题时信笔写下) \(dp[0/1][i][j]\)表示到第\(i\)个时间段时 ...

  10. 项目Beta冲刺(团队3/7)

    项目Beta冲刺(团队) --3/7 作业要求: 项目Beta冲刺(团队) 1.团队信息 团队名 :男上加男 成员信息 : 队员学号 队员姓名 个人博客地址 备注 221600427 Alicesft ...