ฉันจะรับรหัสกระบวนการ Java ของฉันได้อย่างไร
ฉันรู้ว่ามีแฮ็กขึ้นอยู่กับหลายแพลตฟอร์ม แต่ฉันต้องการโซลูชันที่กว้างกว่า
ฉันจะรับรหัสกระบวนการ Java ของฉันได้อย่างไร
ฉันรู้ว่ามีแฮ็กขึ้นอยู่กับหลายแพลตฟอร์ม แต่ฉันต้องการโซลูชันที่กว้างกว่า
คำตอบ:
ไม่มีวิธีที่ไม่ขึ้นกับแพลตฟอร์มที่สามารถรับประกันได้ว่าจะทำงานในการปรับใช้ jvm ทั้งหมด
ManagementFactory.getRuntimeMXBean().getName()
ดูเหมือนโซลูชันที่ใกล้เคียงที่สุด มันสั้นและอาจใช้ได้กับทุกการใช้งานอย่างกว้างขวาง
บน linux + windows จะส่งคืนค่าเช่น12345@hostname
( 12345
เป็น id กระบวนการ) ระวังว่าตามเอกสารไม่มีการรับประกันเกี่ยวกับค่านี้:
ส่งคืนชื่อที่แสดงถึงเครื่องเสมือน Java ที่รันอยู่ สตริงชื่อที่ส่งคืนสามารถเป็นสตริงใดก็ได้และการใช้งานเครื่องเสมือน Java สามารถเลือกที่จะฝังข้อมูลที่เป็นประโยชน์เฉพาะแพลตฟอร์มในสตริงชื่อที่ส่งคืน เครื่องเสมือนที่ใช้งานอยู่แต่ละเครื่องอาจมีชื่อแตกต่างกัน
ใน Java 9 API กระบวนการใหม่สามารถใช้ได้:
long pid = ProcessHandle.current().pid();
คุณสามารถใช้JNA น่าเสียดายที่ไม่มี JNA API ทั่วไปในการรับ ID กระบวนการปัจจุบัน แต่แต่ละแพลตฟอร์มนั้นค่อนข้างง่าย:
ตรวจสอบให้แน่ใจว่าคุณมีjna-platform.jar
แล้ว:
int pid = Kernel32.INSTANCE.GetCurrentProcessId();
ประกาศ:
private interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary("c", CLibrary.class);
int getpid ();
}
แล้ว:
int pid = CLibrary.INSTANCE.getpid();
ภายใต้ Java 9 API กระบวนการใหม่สามารถใช้เพื่อรับ ID กระบวนการปัจจุบัน ก่อนอื่นให้คุณจับที่จับไปยังกระบวนการปัจจุบันจากนั้นสอบถาม PID:
long pid = ProcessHandle.current().pid();
getpid()
วิธีการแก้ปัญหายังทำงานสำหรับ OS X กับโทร JNA กับ "ระบบ" ห้องสมุด
error: cannot find symbol
สำหรับ jdk9
นี่เป็นวิธีแบ็คดอร์ซึ่งอาจใช้ไม่ได้กับ VMs ทั้งหมด แต่ควรใช้ได้กับทั้ง linux และ windows ( ตัวอย่างดั้งเดิมที่นี่ ):
java.lang.management.RuntimeMXBean runtime =
java.lang.management.ManagementFactory.getRuntimeMXBean();
java.lang.reflect.Field jvm = runtime.getClass().getDeclaredField("jvm");
jvm.setAccessible(true);
sun.management.VMManagement mgmt =
(sun.management.VMManagement) jvm.get(runtime);
java.lang.reflect.Method pid_method =
mgmt.getClass().getDeclaredMethod("getProcessId");
pid_method.setAccessible(true);
int pid = (Integer) pid_method.invoke(mgmt);
getDeclaredMethod
jvm.get(runtime)
ลองSigar API ที่กว้างขวางมาก ใบอนุญาต Apache 2
private Sigar sigar;
public synchronized Sigar getSigar() {
if (sigar == null) {
sigar = new Sigar();
}
return sigar;
}
public synchronized void forceRelease() {
if (sigar != null) {
sigar.close();
sigar = null;
}
}
public long getPid() {
return getSigar().getPid();
}
วิธีการต่อไปนี้พยายามดึง PID จากjava.lang.management.ManagementFactory
:
private static String getProcessId(final String fallback) {
// Note: may fail in some JVM implementations
// therefore fallback has to be provided
// something like '<pid>@<hostname>', at least in SUN / Oracle JVMs
final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
final int index = jvmName.indexOf('@');
if (index < 1) {
// part before '@' empty (index = 0) / '@' not found (index = -1)
return fallback;
}
try {
return Long.toString(Long.parseLong(jvmName.substring(0, index)));
} catch (NumberFormatException e) {
// ignore
}
return fallback;
}
โทรเพียงgetProcessId("<PID>")
ตัวอย่างเช่น
สำหรับ JVM รุ่นเก่าใน linux ...
private static String getPid() throws IOException {
byte[] bo = new byte[256];
InputStream is = new FileInputStream("/proc/self/stat");
is.read(bo);
for (int i = 0; i < bo.length; i++) {
if ((bo[i] < '0') || (bo[i] > '9')) {
return new String(bo, 0, i);
}
}
return "-1";
}
int pid = Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
หากคุณกำลังจะไปทำอย่างนั้นแล้วก็ทำ ทำไมต้อง gyrations เพิ่มเติม?
getCanonicalFile()
วิธีการที่แปลง "ตนเอง" เป็น PID?
คุณสามารถตรวจสอบโครงการของฉัน: JavaSysMonบน GitHub มันมี id กระบวนการและสิ่งอื่น ๆ (การใช้งาน CPU, การใช้หน่วยความจำ) ข้ามแพลตฟอร์ม (ปัจจุบันคือ Windows, Mac OSX, Linux และ Solaris)
ตั้งแต่ Java 9 มีเมธอด Process.getPid () ซึ่งส่งคืนเนทีฟไอดีของกระบวนการ:
public abstract class Process {
...
public long getPid();
}
เพื่อรับ ID กระบวนการของกระบวนการ Java ปัจจุบันสามารถใช้ProcessHandle
อินเตอร์เฟส:
System.out.println(ProcessHandle.current().pid());
ในสกาล่า:
import sys.process._
val pid: Long = Seq("sh", "-c", "echo $PPID").!!.trim.toLong
สิ่งนี้จะให้วิธีแก้ปัญหาแก่คุณในระบบ Unix จนกว่า Java 9 จะวางจำหน่าย (ฉันรู้ว่าคำถามเกี่ยวกับ Java แต่เนื่องจากไม่มีคำถามเทียบเท่าสำหรับ Scala ฉันต้องการปล่อยให้ผู้ใช้ Scala ที่อาจสะดุดในคำถามเดียวกัน)
เพื่อความสมบูรณ์มีเสื้อคลุมในSpring Bootสำหรับ
String jvmName = ManagementFactory.getRuntimeMXBean().getName();
return jvmName.split("@")[0];
สารละลาย. หากจำเป็นต้องใช้จำนวนเต็มค่านี้สามารถสรุปได้ถึงหนึ่งซับ:
int pid = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
หากมีใครใช้ Spring boot แล้วเขา / เธออาจใช้org.springframework.boot.ApplicationPid
ApplicationPid pid = new ApplicationPid();
pid.toString();
เมธอด toString () พิมพ์ pid หรือ '???'
คำเตือนที่ใช้ ManagementFactory จะถูกกล่าวถึงในคำตอบอื่น ๆ แล้ว
java.lang.management.ManagementFactory.getRuntimeMXBean().getName().split("@")[0]
public static long getPID() {
String processName = java.lang.management.ManagementFactory.getRuntimeMXBean().getName();
if (processName != null && processName.length() > 0) {
try {
return Long.parseLong(processName.split("@")[0]);
}
catch (Exception e) {
return 0;
}
}
return 0;
}
ล่าสุดที่ฉันพบคือมีคุณสมบัติของระบบที่เรียกsun.java.launcher.pid
ว่ามีอย่างน้อยบน linux JMX bean
แผนของฉันคือการใช้ที่และหากยังไม่พบว่ามีการใช้
ขึ้นอยู่กับว่าคุณต้องการข้อมูลจากที่ไหน
หากคุณกำลังมองหาข้อมูลจากคอนโซลคุณสามารถใช้คำสั่ง jps คำสั่งให้เอาต์พุตคล้ายกับคำสั่ง Unix ps และมาพร้อมกับ JDK ตั้งแต่ฉันเชื่อว่า 1.5
หากคุณกำลังมองจากกระบวนการ RuntimeMXBean (ตามที่กล่าวโดย Wouter Coekaerts) น่าจะเป็นทางเลือกที่ดีที่สุดของคุณ เอาต์พุตจาก getName () บน Windows ที่ใช้ Sun JDK 1.6 u7 อยู่ในรูปแบบ [PROCESS_ID] @ [MACHINE_NAME] อย่างไรก็ตามคุณสามารถลองใช้ jps และแยกวิเคราะห์ผลลัพธ์จาก:
String jps = [JDK HOME] + "\\bin\\jps.exe";
Process p = Runtime.getRuntime().exec(jps);
หากรันโดยไม่มีตัวเลือกเอาต์พุตควรเป็น id กระบวนการตามด้วยชื่อ
นี่คือรหัส JConsole และอาจใช้ jps และ VisualVM มันใช้การเรียนจาก
แพคเกจจากsun.jvmstat.monitor.*
tool.jar
package my.code.a003.process;
import sun.jvmstat.monitor.HostIdentifier;
import sun.jvmstat.monitor.MonitorException;
import sun.jvmstat.monitor.MonitoredHost;
import sun.jvmstat.monitor.MonitoredVm;
import sun.jvmstat.monitor.MonitoredVmUtil;
import sun.jvmstat.monitor.VmIdentifier;
public class GetOwnPid {
public static void main(String[] args) {
new GetOwnPid().run();
}
public void run() {
System.out.println(getPid(this.getClass()));
}
public Integer getPid(Class<?> mainClass) {
MonitoredHost monitoredHost;
Set<Integer> activeVmPids;
try {
monitoredHost = MonitoredHost.getMonitoredHost(new HostIdentifier((String) null));
activeVmPids = monitoredHost.activeVms();
MonitoredVm mvm = null;
for (Integer vmPid : activeVmPids) {
try {
mvm = monitoredHost.getMonitoredVm(new VmIdentifier(vmPid.toString()));
String mvmMainClass = MonitoredVmUtil.mainClass(mvm, true);
if (mainClass.getName().equals(mvmMainClass)) {
return vmPid;
}
} finally {
if (mvm != null) {
mvm.detach();
}
}
}
} catch (java.net.URISyntaxException e) {
throw new InternalError(e.getMessage());
} catch (MonitorException e) {
throw new InternalError(e.getMessage());
}
return null;
}
}
มีจับไม่กี่:
tool.jar
เป็นห้องสมุดกระจายกับ Oracle JDK แต่ไม่ JRE!tool.jar
จาก Maven repo; กำหนดค่าด้วย Maven ค่อนข้างยุ่งยากtool.jar
อาจจะมีขึ้นอยู่กับแพลตฟอร์ม native (?) รหัสดังนั้นจึงไม่สามารถแจกจ่ายได้อย่างง่ายดายUPDATE: ฉันเพิ่งตรวจสอบสองครั้งว่า JPS ใช้วิธีนี้นั่นคือไลบรารี Jvmstat (ส่วนหนึ่งของ tool.jar) ดังนั้นไม่จำเป็นต้องเรียก JPS เป็นกระบวนการภายนอกให้เรียกไลบรารี Jvmstat โดยตรงตามตัวอย่างที่แสดง คุณยังสามารถรับรายชื่อของ JVMs runnin ทั้งหมดบน localhost ด้วยวิธีนี้ ดูซอร์สโค้ด JPS :
ฉันกำลังเพิ่มสิ่งนี้ลงในโซลูชันอื่น
process id
final RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
final long pid = runtime.getPid();
out.println("Process ID is '" + pid);
จากคำตอบของ Ashwin Jayaprakash (+1) เกี่ยวกับ Apache 2.0 ที่ได้รับอนุญาตSIGAR
นี่คือวิธีที่ฉันใช้เพื่อรับ PID ของกระบวนการปัจจุบันเท่านั้น:
import org.hyperic.sigar.Sigar;
Sigar sigar = new Sigar();
long pid = sigar.getPid();
sigar.close();
แม้ว่ามันจะไม่ทำงานบนแพลตฟอร์มทั้งหมดมันไม่ทำงานบนLinux, Windows, OS X และแพลตฟอร์ม Unix ต่าง ๆ ตามที่ระบุไว้ที่นี่
ฉันรู้ว่านี่เป็นเธรดเก่า แต่ฉันต้องการเรียกใช้ API นั้นเพื่อรับ PID (รวมถึงการจัดการอื่น ๆ ของกระบวนการ Java ตอนรันไทม์) กำลังถูกเพิ่มเข้าในคลาส Process ใน JDK 9: http: // openjdk java.net/jeps/102
ฉันพบวิธีแก้ปัญหาที่อาจเป็นเรื่องเล็กน้อยและฉันไม่ได้ลองบนระบบปฏิบัติการอื่นที่ไม่ใช่ Windows 10 แต่ฉันคิดว่ามันน่าสังเกต
หากคุณพบว่าตัวเองทำงานกับJ2V8และ nodejs คุณสามารถเรียกใช้ฟังก์ชั่นจาวาสคริปต์อย่างง่ายซึ่งจะคืนค่า pid ของกระบวนการ java ให้คุณ
นี่คือตัวอย่าง:
public static void main(String[] args) {
NodeJS nodeJS = NodeJS.createNodeJS();
int pid = nodeJS.getRuntime().executeIntegerScript("process.pid;\n");
System.out.println(pid);
nodeJS.release();
}
นี่คือทางออกของฉัน:
public static boolean isPIDInUse(int pid) {
try {
String s = null;
int java_pid;
RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
java_pid = Integer.parseInt(rt.getName().substring(0, rt.getName().indexOf("@")));
if (java_pid == pid) {
System.out.println("In Use\n");
return true;
}
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
return false;
}
นี่คือสิ่งที่ฉันใช้เมื่อฉันมีความต้องการที่คล้ายกัน สิ่งนี้กำหนด PID ของกระบวนการ Java อย่างถูกต้อง ปล่อยให้รหัส java ของคุณวางไข่เซิร์ฟเวอร์ที่หมายเลขพอร์ตที่กำหนดไว้ล่วงหน้าจากนั้นดำเนินการคำสั่งระบบปฏิบัติการเพื่อค้นหาฟัง PID บนพอร์ต สำหรับ Linux
netstat -tupln | grep portNumber