Làm cách nào để tắt ứng dụng Spring Boot đúng cách?


120

Trong Tài liệu khởi động mùa xuân, họ nói rằng 'Mỗi SpringApplication sẽ đăng ký một hook tắt với JVM để đảm bảo rằng ApplicationContext được đóng một cách duyên dáng khi thoát.'

Khi tôi nhấp ctrl+cvào lệnh shell, ứng dụng có thể được tắt một cách duyên dáng. Nếu tôi chạy ứng dụng trong máy sản xuất, tôi phải sử dụng lệnh java -jar ProApplicaton.jar. Nhưng tôi không thể đóng thiết bị đầu cuối shell, nếu không nó sẽ đóng quá trình.

Nếu tôi chạy lệnh like nohup java -jar ProApplicaton.jar &, tôi không ctrl+cthể tắt nó một cách duyên dáng.

Cách chính xác để khởi động và dừng ứng dụng Spring Boot trong môi trường sản xuất là gì?


Tùy thuộc vào cấu hình của bạn, PID của ứng dụng được ghi vào tệp. Bạn có thể gửi tín hiệu kết thúc tới PID đó. Xem thêm các ý kiến ​​trong vấn đề này .
M. Deinum

Tôi nên sử dụng tín hiệu nào, tôi không nghĩ rằng kill -9 là một ý kiến ​​hay, đúng không?
Chris

5
Đó là lý do tại sao tôi chỉ bạn đến chủ đề đó ... Nhưng một cái gì đó giống như kill -SIGTERM <PID>nên làm thủ thuật.
M. Deinum

giết bằng pid, không -9
Dapeng

1
giết $ (lsof tcp -ti: <port>) - trong trường hợp bạn không muốn sử dụng thiết bị truyền động và cần một kill nhanh
Alex Nolasco

Câu trả lời:


61

Nếu bạn đang sử dụng mô-đun bộ truyền động, bạn có thể tắt ứng dụng thông qua JMXhoặc HTTPnếu điểm cuối được bật.

thêm vào application.properties:

endpoints.shutdown.enabled = true

URL sau sẽ có sẵn:

/actuator/shutdown - Cho phép ứng dụng tắt một cách duyên dáng (không được bật theo mặc định).

Tùy thuộc vào cách một điểm cuối được hiển thị, thông số nhạy cảm có thể được sử dụng như một gợi ý bảo mật.

Ví dụ: các điểm cuối nhạy cảm sẽ yêu cầu tên người dùng / mật khẩu khi chúng được truy cập qua HTTP(hoặc đơn giản là bị vô hiệu hóa nếu bảo mật web không được bật).

Từ tài liệu khởi động Spring


1
Tôi không muốn bao gồm mô-đun thiết bị truyền động. Nhưng tôi thấy rằng, trong nhật ký bảng điều khiển của tôi, Spring Boot in PID ở dòng đầu tiên. Có cách nào để Spring Boot in PID trong tệp khác mà không cần thêm mô-đun bộ truyền động (ApplicationPidListener) không?
Chris

2
Lưu ý rằng đây phải là một bài đăng http tới điểm cuối này. Bạn có thể kích hoạt nó với endpoints.shutdown.enabled = true
sparkyspider

54

Đây là một tùy chọn khác không yêu cầu bạn thay đổi mã hoặc để lộ một điểm cuối đã tắt. Tạo các tập lệnh sau và sử dụng chúng để khởi động và dừng ứng dụng của bạn.

start.sh

#!/bin/bash
java -jar myapp.jar & echo $! > ./pid.file &

Khởi động ứng dụng của bạn và lưu id quy trình trong một tệp

stop.sh

#!/bin/bash
kill $(cat ./pid.file)

Dừng ứng dụng của bạn bằng id quy trình đã lưu

start_silent.sh

#!/bin/bash
nohup ./start.sh > foo.out 2> foo.err < /dev/null &

Nếu bạn cần khởi động ứng dụng bằng ssh từ một máy từ xa hoặc đường ống CI thì hãy sử dụng tập lệnh này để khởi động ứng dụng của bạn. Sử dụng start.sh trực tiếp có thể khiến shell bị treo.

Sau khi vd. lại / triển khai ứng dụng của bạn, bạn có thể khởi động lại ứng dụng bằng cách sử dụng:

sshpass -p password ssh -oStrictHostKeyChecking=no userName@www.domain.com 'cd /home/user/pathToApp; ./stop.sh; ./start_silent.sh'

Đây nên là câu trả lời. Tôi vừa xác nhận rằng một tín hiệu 15 tắt máy báo cho mùa xuân sắp tàn một cách duyên dáng.
Chad

1
Tại sao bạn không gọi thực thi java - jar với nohup bên trong start.sh, thay vì gọi thực thi java - jar bên trong start.sh được gọi với nohup bên trong một tập lệnh shell bên ngoài khác ??
Anand Varkey Philips

2
@AnandVarkeyPhilips Lý do duy nhất là đôi khi tôi gọi start.sh từ dòng lệnh cho mục đích thử nghiệm, nhưng nếu bạn luôn cần nohupsau đó bạn chỉ có thể kết hợp các lệnh
Jens

@Jens, Cảm ơn vì thông tin. Bạn có thể cho tôi biết bạn làm việc này không: foo.out 2> foo.err </ dev / null &
Anand Varkey Philips

1
@jens, cảm ơn tôi đã thực hiện thành công và tôi đã đăng tập lệnh bắt đầu và dừng của mình ở đây bên dưới. ( stackoverflow.com/questions/26547532/… )
Anand Varkey Philips,

52

Đối với câu trả lời của @ Jean-Philippe Bond,

đây là một ví dụ nhanh về maven cho người dùng maven để định cấu hình điểm cuối HTTP để tắt ứng dụng web khởi động mùa xuân bằng cách sử dụng spring-boot-starter-actuator để bạn có thể sao chép và dán:

1.Maven pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

2.application.properties:

#No auth  protected 
endpoints.shutdown.sensitive=false

#Enable shutdown endpoint
endpoints.shutdown.enabled=true

Tất cả các điểm cuối được liệt kê ở đây :

3.Gửi phương thức đăng để tắt ứng dụng:

curl -X POST localhost:port/shutdown

Lưu ý bảo mật:

nếu bạn cần phương thức tắt được bảo vệ bằng xác thực, bạn cũng có thể cần

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>

cấu hình chi tiết :


Sau bước thứ hai, khi cố gắng triển khai, gặp thông báo lỗi này: Mô tả: Tham số 0 của phương thức setAuthenticationConfiguration trong org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter yêu cầu bean thuộc loại 'org.springframework.security.config Không thể tìm thấy .annotation.authentication.configuration.AuthenticationConfiguration '. Hành động: Xem xét việc xác định bean thuộc loại 'org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration' trong cấu hình của bạn.
Roberto

2
Xin lưu ý: Nếu tôi đã bao gồm một cái gì đó giống như server.contextPath=/appNametrong application.properties của tôi Vì vậy, bây giờ lệnh tắt máy sẽ trở thành: curl -X POST localhost:8080/appName/shutdown Hy vọng nó có thể giúp ích cho ai đó. Tôi đã phải đấu tranh rất nhiều vì sai lầm này.
Naveen Kumar

Với Spring Boot 1.5.8, nếu không có bảo mật, nên có trong application.properties endpoints.shutdown.enabled=true management.security.enabled=false.
Stefano Scarpanti

Nếu bạn không muốn để lộ điểm cuối và sử dụng tập tin PID để dừng lại và bắt đầu qua shell script, hãy thử này: stackoverflow.com/questions/26547532/...
Anand Varkey Philips

27

Bạn có thể tạo ứng dụng springboot để ghi PID vào tệp và bạn có thể sử dụng tệp pid để dừng hoặc khởi động lại hoặc nhận trạng thái bằng tập lệnh bash. Để ghi PID vào một tệp, hãy đăng ký một trình nghe cho SpringApplication bằng ApplicationPidFileWriter như được hiển thị bên dưới:

SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new ApplicationPidFileWriter("./bin/app.pid"));
application.run();

Sau đó, viết một tập lệnh bash để chạy ứng dụng khởi động mùa xuân. Tham khảo .

Bây giờ bạn có thể sử dụng tập lệnh để bắt đầu, dừng hoặc khởi động lại.


Generic và Jenkins tương thích hoàn toàn bắt đầu và dừng shell script có thể được tìm thấy ở đây ( stackoverflow.com/questions/26547532/... )
Anand Varkey Philips


14

Tất cả các câu trả lời dường như không có thực tế là bạn có thể cần phải hoàn thành một số phần công việc theo cách phối hợp trong thời gian tắt máy (ví dụ: trong một ứng dụng doanh nghiệp).

@PreDestroycho phép bạn thực thi mã tắt trong từng bean. Một cái gì đó phức tạp hơn sẽ trông như thế này:

@Component
public class ApplicationShutdown implements ApplicationListener<ContextClosedEvent> {
     @Autowired ... //various components and services

     @Override
     public void onApplicationEvent(ContextClosedEvent event) {
         service1.changeHeartBeatMessage(); // allows loadbalancers & clusters to prepare for the impending shutdown
         service2.deregisterQueueListeners();
         service3.finishProcessingTasksAtHand();
         service2.reportFailedTasks();
         service4.gracefullyShutdownNativeSystemProcessesThatMayHaveBeenLaunched(); 
         service1.eventLogGracefulShutdownComplete();
     }
}

Đây chỉ là những gì tôi cần. Sau khi thực hiện các ứng dụng, nhấn ctrl-c Cảm ơn @Michal
Claudio Moscoso

8

Tôi không để lộ bất kỳ điểm cuối nào và bắt đầu ( với nohup trong nền và không có tệp được tạo thông qua nohup ) và dừng với shell script (với KILL PID một cách duyên dáng và buộc giết nếu ứng dụng vẫn chạy sau 3 phút ). Tôi chỉ tạo jar thực thi và sử dụng trình viết tệp PID để ghi tệp PID và lưu trữ Jar và Pid trong thư mục có cùng tên với tên ứng dụng và các tập lệnh shell cũng có cùng tên với start và stop ở cuối. Tôi cũng gọi đây là tập lệnh dừng và tập lệnh bắt đầu thông qua đường ống jenkins. Không có vấn đề cho đến nay. Hoạt động hoàn hảo cho 8 ứng dụng (Các tập lệnh rất chung chung và dễ áp ​​dụng cho bất kỳ ứng dụng nào).

Lớp chính

@SpringBootApplication
public class MyApplication {

    public static final void main(String[] args) {
        SpringApplicationBuilder app = new SpringApplicationBuilder(MyApplication.class);
        app.build().addListeners(new ApplicationPidFileWriter());
        app.run();
    }
}

TẬP TIN YML

spring.pid.fail-on-write-error: true
spring.pid.file: /server-path-with-folder-as-app-name-for-ID/appName/appName.pid

Đây là tập lệnh bắt đầu (start-appname.sh):

#Active Profile(YAML)
ACTIVE_PROFILE="preprod"
# JVM Parameters and Spring boot initialization parameters
JVM_PARAM="-Xms512m -Xmx1024m -Dspring.profiles.active=${ACTIVE_PROFILE} -Dcom.webmethods.jms.clientIDSharing=true"
# Base Folder Path like "/folder/packages"
CURRENT_DIR=$(readlink -f "$0")
BASE_PACKAGE="${CURRENT_DIR%/bin/*}"
# Shell Script file name after removing path like "start-yaml-validator.sh"
SHELL_SCRIPT_FILE_NAME=$(basename -- "$0")
# Shell Script file name after removing extension like "start-yaml-validator"
SHELL_SCRIPT_FILE_NAME_WITHOUT_EXT="${SHELL_SCRIPT_FILE_NAME%.sh}"
# App name after removing start/stop strings like "yaml-validator"
APP_NAME=${SHELL_SCRIPT_FILE_NAME_WITHOUT_EXT#start-}

PIDS=`ps aux |grep [j]ava.*-Dspring.profiles.active=$ACTIVE_PROFILE.*$APP_NAME.*jar | awk {'print $2'}`
if [ -z "$PIDS" ]; then
  echo "No instances of $APP_NAME with profile:$ACTIVE_PROFILE is running..." 1>&2
else
  for PROCESS_ID in $PIDS; do
        echo "Please stop the process($PROCESS_ID) using the shell script: stop-$APP_NAME.sh"
  done
  exit 1
fi

# Preparing the java home path for execution
JAVA_EXEC='/usr/bin/java'
# Java Executable - Jar Path Obtained from latest file in directory
JAVA_APP=$(ls -t $BASE_PACKAGE/apps/$APP_NAME/$APP_NAME*.jar | head -n1)
# To execute the application.
FINAL_EXEC="$JAVA_EXEC $JVM_PARAM -jar $JAVA_APP"
# Making executable command using tilde symbol and running completely detached from terminal
`nohup $FINAL_EXEC  </dev/null >/dev/null 2>&1 &`
echo "$APP_NAME start script is  completed."

Đây là tập lệnh dừng (stop-appname.sh):

#Active Profile(YAML)
ACTIVE_PROFILE="preprod"
#Base Folder Path like "/folder/packages"
CURRENT_DIR=$(readlink -f "$0")
BASE_PACKAGE="${CURRENT_DIR%/bin/*}"
# Shell Script file name after removing path like "start-yaml-validator.sh"
SHELL_SCRIPT_FILE_NAME=$(basename -- "$0")
# Shell Script file name after removing extension like "start-yaml-validator"
SHELL_SCRIPT_FILE_NAME_WITHOUT_EXT="${SHELL_SCRIPT_FILE_NAME%.*}"
# App name after removing start/stop strings like "yaml-validator"
APP_NAME=${SHELL_SCRIPT_FILE_NAME_WITHOUT_EXT:5}

# Script to stop the application
PID_PATH="$BASE_PACKAGE/config/$APP_NAME/$APP_NAME.pid"

if [ ! -f "$PID_PATH" ]; then
   echo "Process Id FilePath($PID_PATH) Not found"
else
    PROCESS_ID=`cat $PID_PATH`
    if [ ! -e /proc/$PROCESS_ID -a /proc/$PROCESS_ID/exe ]; then
        echo "$APP_NAME was not running with PROCESS_ID:$PROCESS_ID.";
    else
        kill $PROCESS_ID;
        echo "Gracefully stopping $APP_NAME with PROCESS_ID:$PROCESS_ID..."
        sleep 5s
    fi
fi
PIDS=`/bin/ps aux |/bin/grep [j]ava.*-Dspring.profiles.active=$ACTIVE_PROFILE.*$APP_NAME.*jar | /bin/awk {'print $2'}`
if [ -z "$PIDS" ]; then
  echo "All instances of $APP_NAME with profile:$ACTIVE_PROFILE has has been successfully stopped now..." 1>&2
else
  for PROCESS_ID in $PIDS; do
    counter=1
    until [ $counter -gt 150 ]
        do
            if ps -p $PROCESS_ID > /dev/null; then
                echo "Waiting for the process($PROCESS_ID) to finish on it's own for $(( 300 - $(( $counter*5)) ))seconds..."
                sleep 2s
                ((counter++))
            else
                echo "$APP_NAME with PROCESS_ID:$PROCESS_ID is stopped now.."
                exit 0;
            fi
    done
    echo "Forcefully Killing $APP_NAME with PROCESS_ID:$PROCESS_ID."
    kill -9 $PROCESS_ID
  done
fi

7

Spring Boot cung cấp một số trình nghe ứng dụng trong khi cố gắng tạo ngữ cảnh ứng dụng, một trong số đó là ApplicationFailedEvent. Chúng ta có thể sử dụng để biết thời tiết mà ngữ cảnh ứng dụng đã khởi tạo hay chưa.

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.boot.context.event.ApplicationFailedEvent; 
    import org.springframework.context.ApplicationListener;

    public class ApplicationErrorListener implements 
                    ApplicationListener<ApplicationFailedEvent> {

        private static final Logger LOGGER = 
        LoggerFactory.getLogger(ApplicationErrorListener.class);

        @Override
        public void onApplicationEvent(ApplicationFailedEvent event) {
           if (event.getException() != null) {
                LOGGER.info("!!!!!!Looks like something not working as 
                                expected so stoping application.!!!!!!");
                         event.getApplicationContext().close();
                  System.exit(-1);
           } 
        }
    }

Thêm vào lớp trình nghe ở trên vào SpringApplication.

    new SpringApplicationBuilder(Application.class)
            .listeners(new ApplicationErrorListener())
            .run(args);  

Câu trả lời tốt nhất mà tôi tìm thấy! Cảm ơn bạn!
Vagif

[@ user3137438], Nó khác với đăng nhập bên trong chú thích hủy hủy trước như thế nào?
Anand Varkey Philips

6

Kể từ Spring Boot 2.3 trở lên, có một cơ chế tắt duyên dáng được tích hợp sẵn .

Pre-Spring Boot 2.3 , không có cơ chế tắt máy duyên dáng bên ngoài. Một số bộ khởi động spring-boot cung cấp chức năng này:

  1. https://github.com/jihor/hiatus-spring-boot
  2. https://github.com/gesellix/graceful-shutdown-spring-boot
  3. https://github.com/corentin59/spring-boot-graceful-shutdown

Tôi là tác giả của nr. 1. Khởi động có tên là "Hiatus for Spring Boot". Nó hoạt động ở mức cân bằng tải, tức là chỉ cần đánh dấu dịch vụ là OUT_OF_SERVICE, không can thiệp vào ngữ cảnh ứng dụng theo bất kỳ cách nào. Điều này cho phép thực hiện một thời gian ngừng hoạt động và có nghĩa là, nếu được yêu cầu, dịch vụ có thể ngừng hoạt động trong một thời gian và sau đó hoạt động trở lại. Nhược điểm là nó không dừng JVM, bạn sẽ phải thực hiện bằng killlệnh. Khi tôi chạy mọi thứ trong vùng chứa, điều này không có gì to tát đối với tôi, vì dù sao thì tôi cũng sẽ phải dừng lại và loại bỏ vùng chứa.

Số 2 và 3 ít nhiều dựa trên bài đăng này của Andy Wilkinson. Chúng hoạt động một chiều - sau khi được kích hoạt, cuối cùng chúng sẽ đóng bối cảnh.


5

SpringApplication đăng ký ngầm một hook tắt với JVM để đảm bảo rằng ApplicationContext được đóng một cách duyên dáng khi thoát. Điều đó cũng sẽ gọi tất cả các phương thức bean được chú thích bằng @PreDestroy. Điều đó có nghĩa là chúng ta không phải sử dụng rõ ràng registerShutdownHook()phương thức của một ConfigurableApplicationContextứng dụng khởi động, giống như chúng ta phải làm trong ứng dụng lõi mùa xuân.

@SpringBootConfiguration
public class ExampleMain {
    @Bean
    MyBean myBean() {
        return new MyBean();
    }

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(ExampleMain.class, args);
        MyBean myBean = context.getBean(MyBean.class);
        myBean.doSomething();

        //no need to call context.registerShutdownHook();
    }

    private static class MyBean {

        @PostConstruct
        public void init() {
            System.out.println("init");
        }

        public void doSomething() {
            System.out.println("in doSomething()");
        }

        @PreDestroy
        public void destroy() {
            System.out.println("destroy");
        }
    }
}

Để thay thế @PostConstruct@PreDestroytôi đã sử dụng các thuộc tính initMethoddestroyMethodtrong @Beanchú thích. Vì vậy, trong ví dụ này: @Bean(initMethod="init", destroyMethod="destroy").
acker

Một điều mà @PreDestroyít nhà phát triển có thể không biết là, các phương thức như vậy chỉ được gọi cho các bean với phạm vi Singleton. Các nhà phát triển phải quản lý phần dọn dẹp của vòng đời bean cho các phạm vi khác
asgs

2

Có nhiều cách để tắt ứng dụng mùa xuân. Một là gọi close () trên ApplicationContext:

ApplicationContext ctx =
    SpringApplication.run(HelloWorldApplication.class, args);
// ...
ctx.close()

Câu hỏi của bạn gợi ý rằng bạn muốn đóng ứng dụng của mình bằng cách thực hiện Ctrl+C, điều này thường được sử dụng để chấm dứt một lệnh. Trong trường hợp này...

Sử dụng endpoints.shutdown.enabled=truekhông phải là công thức tốt nhất. Nó có nghĩa là bạn để lộ một điểm cuối để chấm dứt ứng dụng của mình. Vì vậy, tùy thuộc vào trường hợp sử dụng và môi trường của bạn, bạn sẽ phải bảo mật nó ...

Ctrl+Csẽ hoạt động rất tốt trong trường hợp của bạn. Tôi cho rằng vấn đề của bạn là do dấu và (&) Giải thích thêm:

Bối cảnh ứng dụng mùa xuân có thể đã đăng ký một móc tắt với thời gian chạy JVM. Xem tài liệu ApplicationContext .

Tôi không biết liệu Spring Boot có tự động cấu hình hook này như bạn đã nói hay không. Tôi cho rằng đúng như vậy.

Khi bật Ctrl+C, trình bao của bạn sẽ gửi một INTtín hiệu đến ứng dụng nền trước. Nó có nghĩa là "hãy làm gián đoạn việc thực hiện của bạn". Ứng dụng có thể bẫy tín hiệu này và thực hiện dọn dẹp trước khi kết thúc (hook được Spring đăng ký) hoặc đơn giản là bỏ qua nó (xấu).

nohuplà lệnh thực hiện chương trình sau với một bẫy để bỏ qua tín hiệu HUP. HUP được sử dụng để kết thúc chương trình khi bạn treo máy (ví dụ: đóng kết nối ssh của bạn). Hơn nữa, nó chuyển hướng kết quả đầu ra để tránh chương trình của bạn chặn trên một TTY đã biến mất. nohupKHÔNG bỏ qua tín hiệu INT. Vì vậy, nó KHÔNG ngăn cản Ctrl+Choạt động.

Tôi cho rằng sự cố của bạn là do dấu và (&), không phải do nohup. Ctrl+Cgửi một tín hiệu đến các quy trình nền trước. Dấu và khiến ứng dụng của bạn được chạy trong nền. Một giải pháp: làm

kill -INT pid

Sử dụng kill -9hoặc kill -KILLkhông tốt bởi vì ứng dụng (ở đây là JVM) không thể bẫy nó để kết thúc một cách duyên dáng.

Một giải pháp khác là đưa ứng dụng của bạn trở lại nền trước. Sau đó Ctrl+Csẽ làm việc. Xem xét kiểm soát Bash Job, chính xác hơn fg.


2

Sử dụng exit()phương thức tĩnh trong lớp SpringApplication để đóng ứng dụng khởi động mùa xuân của bạn một cách duyên dáng.

public class SomeClass {
    @Autowire
    private ApplicationContext context

    public void close() {
        SpringApplication.exit(context);
    }
}

Điều này làm việc cho tôi. Cảm ơn bạn rất nhiều.
Khachornchit Songsaen

1

Spring Boot hiện đã hỗ trợ tắt mở rộng (hiện đang ở phiên bản phát hành trước, 2.3.0.BUILD-SNAPSHOT)

Khi được bật, việc tắt ứng dụng sẽ bao gồm thời gian gia hạn trong khoảng thời gian có thể định cấu hình. Trong thời gian gia hạn này, các yêu cầu hiện có sẽ được phép hoàn thành nhưng không cho phép yêu cầu mới

Bạn có thể kích hoạt nó bằng:

server.shutdown.grace-period=30s

https://docs.spring.io/spring-boot/docs/2.3.0.BUILD-SNAPSHOT/reference/html/spring-boot-features.html#boot-features-graceful-shutdown


0

Nếu bạn đang sử dụng maven, bạn có thể sử dụng plugin Maven App lắp ráp .

Daemon mojo (nhúng JSW ) sẽ xuất ra một tập lệnh shell với đối số start / stop. Nó stopsẽ tắt / giết một cách duyên dáng ứng dụng Spring của bạn.

Tập lệnh tương tự có thể được sử dụng để sử dụng ứng dụng maven của bạn như một dịch vụ linux.


0

Nếu bạn đang ở trong môi trường linux, tất cả những gì bạn phải làm là tạo một liên kết tượng trưng cho tệp .jar của bạn từ bên trong /etc/init.d/

sudo ln -s /path/to/your/myboot-app.jar /etc/init.d/myboot-app

Sau đó, bạn có thể khởi động ứng dụng giống như bất kỳ dịch vụ nào khác

sudo /etc/init.d/myboot-app start

Để đóng ứng dụng

sudo /etc/init.d/myboot-app stop

Bằng cách này, ứng dụng sẽ không kết thúc khi bạn thoát khỏi thiết bị đầu cuối. Và ứng dụng sẽ tắt một cách duyên dáng với lệnh dừng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.