Tắt ứng dụng Spring Boot theo chương trình


109

Làm thế nào tôi có thể lập trình tắt máy một mùa xuân Boot ứng dụng mà không chấm dứt VM ?

Trong các tác phẩm khác, điều ngược lại với

new SpringApplication(Main.class).run(args);

1
Điểm tốt! Gọi close () trên đó sẽ thực hiện công việc.
Axel Fontaine,


@AnandVarkeyPhilips Không, chắc chắn là không. Cái này là về một API, cái kia là về cách để các hoạt động làm như vậy.
Axel Fontaine

Được rồi .. Liên kết câu hỏi đó có thể giúp ích cho những người khác. Bạn có muốn tôi xóa bình luận trên không?
Anand Varkey Philips

Câu trả lời:


111

Đóng một SpringApplicationcơ bản có nghĩa là đóng cơ bản ApplicationContext. Các SpringApplication#run(String...)phương pháp mang đến cho bạn mà ApplicationContextnhư một ConfigurableApplicationContext. Sau đó bạn có thể close()tự mình.

Ví dụ,

@SpringBootApplication
public class Example {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(Example.class, args);
        // ...determine it's time to shut down...
        ctx.close();
    }
}

Ngoài ra, bạn có thể sử dụng static SpringApplication.exit(ApplicationContext, ExitCodeGenerator...)phương pháp trợ giúp để làm điều đó cho bạn. Ví dụ,

@SpringBootApplication
public class Example {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(Example.class, args);
        // ...determine it's time to stop...
        int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() {
            @Override
            public int getExitCode() {
                // no errors
                return 0;
            }
        });

        // or shortened to
        // int exitCode = SpringApplication.exit(ctx, () -> 0);

        System.exit(exitCode);
    }
}

1
Nếu tôi sử dụng ctx.close (); không cần phải gọi System.exit (n) ở cuối phải không? context close () nên có System.exit () bên trong?
chối

2
@Denys Không, ngữ cảnh không thoát khỏi quá trình java khi đóng. Lối ra trong ví dụ của tôi chỉ chứng minh cách ExitCodeGeneratorcó thể được sử dụng. Bạn chỉ có thể quay lại từ mainphương thức để thoát một cách duyên dáng (thoát mã 0).
Sotirios Delimanolis

78

Trong một ứng dụng khởi động mùa xuân, bạn có thể sử dụng một cái gì đó như thế này

ShutdownManager.java

import org.springframework.context.ApplicationContext;
import org.springframework.boot.SpringApplication;

@Component
class ShutdownManager{

    @Autowired
    private ApplicationContext appContext;

    public void initiateShutdown(int returnCode){
        SpringApplication.exit(appContext, () -> returnCode);
    }
}

16
Ủng hộ vì cho thấy rằng ApplicationContextcó thể tự động tiêm vào hạt đậu khác.
Anthony Chuinard

1
@snovelli làm cách nào để gọi phương thức tắt khởi tạo? khởi tạoShutdown (x), x = 0?
StackOverFlow

Khi có điều kiện tắt máy, điều này có thể được thực hiện. SpringApplication.run (..). Close () sẽ hoạt động khi chương trình hoàn thành.
Abubacker Siddik

tại sao SpringApplication. (appContext, () -> returnCode); tại sao appContext.close () không được. Sự khác biệt là gì ?
Rams

@StackOverFlow Bạn cần đưa bean vào nơi bạn cần và sau đó chuyển mã trả về như bạn đã đề xuất (x = 0) nếu nó tắt đúng cách. Ví dụ: bạn có thể đưa Trình quản lý tắt máy vào RestController và cho phép tắt máy từ xa hoặc bạn có thể đưa nó vào theo dõi kiểm tra sức khỏe sẽ tắt JVM trong trường hợp thiếu các dịch vụ hạ lưu
snovelli

36

Điều này làm việc, thậm chí được thực hiện được in.

  SpringApplication.run(MyApplication.class, args).close();
  System.out.println("done");

Vì vậy, thêm .close()saurun()

Giải trình:

public ConfigurableApplicationContext run(String... args)

Chạy ứng dụng Spring, tạo và làm mới một ApplicationContext mới. Thông số:

args - các đối số ứng dụng (thường được truyền từ một phương thức chính của Java)

Trả về: một ApplicationContext đang chạy

và:

void close()Đóng ngữ cảnh ứng dụng này, giải phóng tất cả tài nguyên và khóa mà việc triển khai có thể giữ lại. Điều này bao gồm việc phá hủy tất cả các hạt singleton được lưu trong bộ nhớ cache. Lưu ý: Không gọi đóng trên ngữ cảnh mẹ; ngữ cảnh mẹ có vòng đời riêng, độc lập.

Phương thức này có thể được gọi nhiều lần mà không có tác dụng phụ: Các lệnh gọi đóng tiếp theo trên ngữ cảnh đã đóng sẽ bị bỏ qua.

Vì vậy, về cơ bản, nó sẽ không đóng ngữ cảnh gốc, đó là lý do tại sao VM không thoát.


2
Chỉ xin nhắc lại rằng giải pháp này hoạt động cho quá trình tồn tại ngắn như hàng loạt, nhưng không sử dụng điều này trên các ứng dụng Spring MVC. Ứng dụng chỉ tắt sau khi khởi động.
Michael COLL

@MichaelCOLL câu hỏi là về cách tắt chương trình ứng dụng khởi động lò xo bất kể loại nào. Nó cũng hoạt động cho Spring MVC
ACV

1
@ACV Bạn nói đúng, nó hoạt động, nó hoạt động rất tốt. Nhưng đối với một ứng dụng phải hoạt động (như ứng dụng Spring MVC), tôi nghĩ, đó không phải là cách tốt để làm điều này. Trong trường hợp của tôi, tôi đã sử dụng SpringApplication.exit(appContext, () -> returnCode).
Michael COLL

1
Bạn đang đề cập đến máy ảo nào trong dòng cuối cùng của mình? Nếu bạn đang khởi động ứng dụng Spring Boot bằng SpringApplication.run(MyApplication.class, args), thì không có ngữ cảnh gốc. Chỉ có một ngữ cảnh duy nhất, bối cảnh được tạo và trả lại bởi runbạn, sau đó bạn ngay lập tức close. @Michael nói đúng. Điều này sẽ không hoạt động đối với các chương trình cần thực hiện bất kỳ điều gì sau khi ngữ cảnh Spring được khởi tạo, đây là hầu hết các chương trình.
Savior

@Savior JVM. Có một ngữ cảnh cha mẹ. Ở đây chúng ta đang nói về cách tắt ứng dụng khởi động Spring. Bạn thường không tắt các ứng dụng web theo cách này. Vì vậy, cơ chế này thường được sử dụng cho các ứng dụng tồn tại trong thời gian ngắn cần dừng lại. Theo mặc định, Spring boot sẽ tiếp tục chạy ngay cả sau khi bạn hoàn thành quá trình xử lý hàng loạt, vì vậy đó là nơi bạn muốn sử dụng cơ chế này.
ACV

3

Trong ứng dụng bạn có thể sử dụng SpringApplication. Phương thức này có một exit()phương thức tĩnh nhận hai đối số: the ApplicationContextvà an ExitCodeGenerator:

tức là bạn có thể khai báo phương thức này:

@Autowired
public void shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) {
    SpringApplication.exit(applicationContext, exitCodeGenerator);
}

Trong các bài kiểm tra Tích hợp, bạn có thể đạt được nó bằng cách thêm @DirtiesContextchú thích ở cấp lớp:

  • @DirtiesContext(classMode=ClassMode.AFTER_CLASS) - ApplicationContext được liên kết sẽ bị đánh dấu là bẩn sau lớp thử nghiệm.
  • @DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) - ApplicationContext được liên kết sẽ bị đánh dấu là bẩn sau mỗi phương thức kiểm tra trong lớp.

I E

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {Application.class},
    webEnvironment= SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {"server.port:0"})
@DirtiesContext(classMode= DirtiesContext.ClassMode.AFTER_CLASS)
public class ApplicationIT {
...

Đồng ý. Tôi phải lấy ExecutorServiceExitCodeGenerator ở đâu? Nếu đó là bean, bạn có thể hiển thị đoạn mã tạo (và nó được tạo từ lớp nào) không? Phương thức shutDown (ExecutorServiceExitCodeGenerator exitCodeGenerator) nên được đặt trong lớp nào?
Vlad G.

2

Điều này sẽ đảm bảo rằng ứng dụng SpringBoot được đóng đúng cách và các tài nguyên được giải phóng trở lại hệ điều hành,

@Autowired
private ApplicationContext context;

@GetMapping("/shutdown-app")
public void shutdownApp() {

    int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
    System.exit(exitCode);
}
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.