2009-02-10 40 views
67

Tôi có một chương trình Java mà tôi muốn daemonize trên một hệ thống Linux. Nói cách khác, tôi muốn bắt đầu chạy nó trong một hệ vỏ và có nó tiếp tục chạy sau khi tôi đã đăng xuất. Tôi cũng muốn có thể dừng chương trình một cách sạch sẽ.Làm thế nào để Daemonize một chương trình Java?

Tôi đã tìm thấy this article sử dụng kết hợp mã shell và mã Java để thực hiện thủ thuật. Nó có vẻ tốt, nhưng tôi muốn một cái gì đó đơn giản, nếu có thể.

Phương pháp ưa thích của bạn để daemonize một chương trình Java trên hệ thống Linux là gì?

+0

Vui lòng xem http://stackoverflow.com/questions/407016/how-to-convert-an-existing-java-application-to-a-sys-v-service-daemon –

+6

Thử 'nohup java prog &' . – ceving

+0

Một cách sạch hơn để quản lý dịch vụ tại UNIX https://cr.yp.to/daemontools.html – Velu

Trả lời

36

Apache Commons Daemon sẽ chạy chương trình Java của bạn dưới dạng trình nền Linux hoặc Dịch vụ WinNT.

5

Bạn có thể thử Java Service Wrapper, ấn bản cộng đồng miễn phí và đáp ứng nhu cầu của bạn.

+1

Làm thế nào để bạn biết nó đáp ứng nhu cầu của mình? Các dịch vụ Java Wrapper không phải là miễn phí cho sử dụng thương mại theo giấy phép của nó: http://wrapper.tanukisoftware.com/doc/english/licenseOverview.html – Jared

14

Tôi thích lệnh nohup. Bài đăng trên blog cho biết có nhiều cách tốt hơn, nhưng tôi không nghĩ chúng đủ tốt hơn.

+0

Nó không phải là hoàn toàn daemonizing .. Điều gì sẽ xảy ra nếu hệ điều hành được khởi động lại? giải pháp sạch hơn với daemontools http://stackoverflow.com/a/35569052/1840774 – Velu

+1

điều này sẽ không mang lại dịch vụ khi hệ thống bị hỏng hoặc khởi động lại! – Velu

3

Điều đó tùy thuộc. Nếu nó chỉ là một điều một lần, tôi muốn daemonize nó và sau đó về nhà, nhưng thường tôi chờ kết quả, tôi có thể làm:

nohup java com.me.MyProgram & 

tại dòng lệnh. Để giết nó sạch sẽ, bạn có rất nhiều lựa chọn. Bạn có thể có một người nghe cho SIGKILL, hoặc nghe trên một cổng và tắt máy khi kết nối được thực hiện, định kỳ kiểm tra một tập tin. Cách tiếp cận khác biệt có điểm yếu khác nhau. Nếu nó được sử dụng trong sản xuất, tôi muốn cung cấp cho nó nhiều suy nghĩ, và có lẽ ném một kịch bản vào /etc/init.d rằng nohups nó, và có một tắt tinh vi hơn, chẳng hạn như những gì tomcat có.

+0

Vâng, nó không phải là hoàn toàn daemonizing .. Điều gì nếu hệ điều hành được khởi động lại ?.Đây là giải pháp sạch hơn với daemontools http://stackoverflow.com/a/35569052/1840774 – Velu

23

Tôi thường xuyên thấy mình viết kịch bản hoặc dòng lệnh mà thực chất giống như thế này, nếu tôi muốn:

  1. Chạy một chương trình đó là miễn dịch với sighups
  2. Đó là hoàn toàn bị ngắt kết nối từ vỏ mà spawn nó, và
  3. Tạo tệp nhật ký từ stderr và stdout nội dung được hiển thị, nhưng
  4. Cho phép tôi dừng xem quá trình đăng nhập và thực hiện các nội dung khác mà không làm gián đoạn quá trình chạy

Thưởng thức.

nohup java com.me.MyProgram </dev/null 2>&1 | tee logfile.log &
+5

điều này sẽ không mang lại dịch vụ khi hệ thống đi xuống hoặc bị rơi .. – Velu

+0

Bạn có thể bắt đầu bằng cron và tính năng @reboot. – Sven

30

Nếu bạn không thể dựa vào Java Service Wrapper trích dẫn elsewhere (ví dụ, nếu bạn đang chạy trên Ubuntu, trong đó có không có phiên bản đóng gói của SW), bạn có thể muốn làm điều đó theo cách cũ thời: có chương trình của bạn viết PID của nó trong /var/run/$progname.pid, và viết một kịch bản init chuẩn SysV (sử dụng ví dụ cho một ntpd làm ví dụ, nó đơn giản) xung quanh nó. Tốt hơn, làm cho nó tương thích với LSB.

Về cơ bản, hàm bắt đầu kiểm tra nếu chương trình đã chạy (bằng cách kiểm tra nếu /var/run/$progname.pid tồn tại và nội dung của tệp đó là PID của tiến trình đang chạy) và nếu không chạy

logfile=/var/log/$progname.log 
pidfile=/var/run/$progname.pid 
nohup java -Dpidfile=$pidfile $jopts $mainClass </dev/null > $logfile 2>&1 

các kiểm tra chức năng dừng trên /var/run/$progname.pid, kiểm tra nếu tập tin đó là PID của một quá trình hoạt động, xác nhận rằng nó là một máy ảo Java (như vậy là không để giết một quá trình đơn giản chỉ cần sử dụng lại PID từ một trường hợp chết của daemon Java của tôi) và sau đó giết chết quá trình đó.

Khi được gọi, phương thức main() của tôi sẽ bắt đầu bằng cách viết PID của nó trong tệp được định nghĩa trong System.getProperty ("pidfile").

Một rào cản lớn, mặc dù:. Trong Java, không có cách nào đơn giản và tiêu chuẩn để có được PID của tiến trình JVM chạy trong

Dưới đây là những gì tôi đã đưa ra:

private static String getPid() { 
    File proc_self = new File("/proc/self"); 
    if(proc_self.exists()) try { 
     return proc_self.getCanonicalFile().getName(); 
    } 
    catch(Exception e) { 
     /// Continue on fall-back 
    } 
    File bash = new File("/bin/bash"); 
    if(bash.exists()) { 
     ProcessBuilder pb = new ProcessBuilder("/bin/bash","-c","echo $PPID"); 
     try { 
      Process p = pb.start(); 
      BufferedReader rd = new BufferedReader(new InputStreamReader(p.getInputStream())); 
      return rd.readLine(); 
     } 
     catch(IOException e) { 
      return String.valueOf(Thread.currentThread().getId()); 
     } 
    } 
    // This is a cop-out to return something when we don't have BASH 
    return String.valueOf(Thread.currentThread().getId()); 
} 
+8

Không cần Java để viết PID, kịch bản cũng có thể làm điều đó (echo $!> /var/run/my.pid) Ngoài ra, vì thường chỉ root mới có thể ghi vào/var/run, bạn có thể có shell script chạy dưới dạng root và daemon chạy như một người dùng khác. –

+0

Ngoại trừ bạn không thể thay đổi uid hoặc euid trong java, vì vậy bạn phải làm điều đó từ trình bao, với sudo ... đó là một chút đau nếu bạn hỏi tôi. Nó dễ dàng hơn để có/var/run và var/log ghi cho người dùng mà bạn chạy như ... – Varkhan

+3

Ngoài ra, lý do để có Java ghi tệp pid/tệp khóa là có ý nghĩa để biết liệu giai đoạn khởi tạo của daemon đã hoàn thành thành công (bằng cách viết vào cuối giai đoạn đó). – Varkhan

2

This câu hỏi là về daemonizing một chương trình tùy ý (không java cụ thể) vì vậy một số các câu trả lời có thể áp dụng đối với trường hợp của bạn:

0

Nếu bạn thích công cụ mới, bạn có thể thử Akuma. Đối với (ít) thông tin xem thêm Kohsuke Kawaguchi's Blog.

+1

Liên kết của bạn dường như là một nạn nhân trong mối thù của Kohsuke với Oracle. Đây là liên kết mới trên trang cá nhân của anh ấy: http://akuma.kohsuke.org/ –

+0

@CoreyCole: đã cập nhật, cảm ơn bạn! – mark

4

Cách ưa thích của tôi trên Ubuntu là sử dụng tiện ích 'daemon' libslack. Đây là những gì Jenkins sử dụng trên Ubuntu (đó là nơi tôi có ý tưởng.) Tôi đã sử dụng nó cho các ứng dụng máy chủ dựa trên Jetty của tôi và nó hoạt động tốt.

Khi bạn dừng quá trình daemon, nó sẽ báo hiệu JVM tắt máy. Bạn có thể thực thi mã shutdown/cleanup tại thời điểm này bằng cách đăng ký hook shutdown với Runtime.addShutdownHook().

2

daemontools: - Một cách sạch hơn để quản lý dịch vụ tại UNIX https://cr.yp.to/daemontools.html

  1. Cài đặt công cụ daemon từ url https://cr.yp.to/daemontools/install.html làm theo hướng dẫn nêu ở đó, đối với bất kỳ vấn đề xin vui lòng thử hướng dẫn https://gist.github.com/rizkyabdilah/8516303

  2. Tạo một tệp tại số /etc/init/svscan.conf và thêm các dòng dưới đây (chỉ yêu cầu cho cent-os-6.7)

start on runlevel [12345] 
stop on runlevel [^12345] 
respawn 
exec /command/svscanboot 
  1. Tạo một kịch bản mới có tên chạy bên trong/dịch vụ/vm/thư mục và thêm những dòng dưới đây.
#!/bin/bash  
echo starting VM 
exec java -jar 
/root/learning-/daemon-java/vm.jar 

Lưu ý: thay thế Jar với file Jar của riêng bạn. hoặc bất kỳ tệp lớp java nào.

  1. Khởi động lại hệ thống

  2. svstat/dịch vụ/vm nên dậy và chạy ngay bây giờ!.

  3. svc -d/service/vm nên mang vm xuống ngay bây giờ!
  4. svc -u/service/vm sẽ mang vm ngay bây giờ!
Các vấn đề liên quan