ปิดแอปพลิเคชัน Spring Boot โดยทางโปรแกรม


111

ฉันสามารถเขียนโปรแกรมปิดฤดูใบไม้ผลิ Bootแอพลิเคชันโดยไม่ต้องยกเลิก VM ?

ในงานอื่น ๆ สิ่งที่ตรงกันข้ามกับ

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

1
จุดดี! การเรียก close () ที่ควรจะทำงาน
Axel Fontaine


@AnandVarkeyPhilips ไม่มันไม่แน่นอน อันนี้เกี่ยวกับ API ส่วนอีกอันเกี่ยวกับวิธีการสำหรับ ops ในการทำเช่นนั้น
Axel Fontaine

โอเค .. ลิงก์คำถามนั้นอาจช่วยคนอื่นได้ คุณต้องการให้ฉันลบความคิดเห็นด้านบนหรือไม่?
Anand Varkey Philips

คำตอบ:


111

ปิดโดยทั่วไปหมายถึงการปิดพื้นฐานSpringApplication วิธีช่วยให้คุณทราบว่าเป็น จากนั้นคุณสามารถทำได้ด้วยตัวเองApplicationContextSpringApplication#run(String...)ApplicationContextConfigurableApplicationContextclose()

ตัวอย่างเช่น,

@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();
    }
}

หรือคุณสามารถใช้static SpringApplication.exit(ApplicationContext, ExitCodeGenerator...)วิธีการช่วยเหลือเพื่อดำเนินการให้คุณได้ ตัวอย่างเช่น,

@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
ถ้าฉันใช้ ctx.close (); ไม่จำเป็นต้องเรียก System.exit (n) ต่อท้ายใช่ไหม บริบทปิด () ควรมี System.exit () อยู่ข้างใน?
เด

2
@Denys ไม่บริบทไม่ออกจากกระบวนการ java เมื่อปิด ทางออกในตัวอย่างของฉันแสดงให้เห็นถึงวิธีการExitCodeGeneratorใช้งาน คุณสามารถกลับจากmainวิธีการเพื่อออกอย่างสง่างาม (ออกจากรหัส 0)
Sotirios Delimanolis

80

ในแอปพลิเคชันสปริงบูตคุณสามารถใช้สิ่งนี้ได้

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
โหวตให้แสดงว่าApplicationContextสามารถฉีดถั่วอื่นได้โดยอัตโนมัติ
Anthony Chuinard

1
@snovelli วิธีการเรียกใช้วิธีการปิดเครื่องเริ่มต้น? initiateShutdown (x), x = 0?
StackOverFlow

เมื่อมีการปิดระบบตามเงื่อนไขสามารถดำเนินการได้ SpringApplication.run (.. ). close () จะทำตามที่โปรแกรมเสร็จสิ้น
Abubacker Siddik

ทำไม SpringApplication. (appContext, () -> returnCode); ทำไม appContext.close () ไม่ได้ อะไรคือความแตกต่าง ?
แรมส์

@StackOverFlow คุณต้องฉีด bean ในที่ที่คุณต้องการแล้วส่งรหัสส่งคืนตามที่คุณแนะนำ (x = 0) หากปิดอย่างถูกต้อง ตัวอย่างเช่นคุณสามารถฉีด Shutdown Manager ลงใน RestController และอนุญาตให้ปิดระบบจากระยะไกลหรือคุณสามารถฉีดเข้าไปในการตรวจสอบสุขภาพที่จะปิด JVM ลงในกรณีที่ไม่มีบริการดาวน์สตรีม
snovelli

37

งานนี้พิมพ์เสร็จแล้ว

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

ดังนั้นการเพิ่ม.close()หลังจากrun()

คำอธิบาย:

public ConfigurableApplicationContext run(String... args)

เรียกใช้แอปพลิเคชัน Spring สร้างและรีเฟรช ApplicationContext ใหม่ พารามิเตอร์:

args - อาร์กิวเมนต์ของแอปพลิเคชัน (โดยปกติจะส่งมาจาก Java main method)

ผลตอบแทน: ApplicationContext ที่กำลังรัน

และ:

void close()ปิดบริบทของแอปพลิเคชันนี้ปล่อยทรัพยากรทั้งหมดและล็อกที่การใช้งานอาจมีอยู่ ซึ่งรวมถึงการทำลายถั่วซิงเกิลตันที่เก็บไว้ทั้งหมด หมายเหตุ: ห้ามเรียกปิดบนบริบทหลัก บริบทหลักมีวงจรชีวิตของตนเองและเป็นอิสระ

วิธีนี้สามารถเรียกใช้ได้หลายครั้งโดยไม่มีผลข้างเคียง: การโทรปิดตามมาในบริบทที่ปิดไปแล้วจะถูกละเว้น

โดยพื้นฐานแล้วจะไม่ปิดบริบทหลักนั่นคือสาเหตุที่ VM ไม่ปิด


2
ขอเตือนว่าโซลูชันนี้ใช้ได้กับกระบวนการที่มีอายุสั้นเช่นแบทช์ แต่อย่าใช้กับแอปพลิเคชัน Spring MVC แอปพลิเคชันเพิ่งปิดเครื่องหลังจากบูต
Michael COLL

@MichaelCOLL คำถามเกี่ยวกับวิธีปิดแอปสปริงบูตโดยใช้โปรแกรมโดยไม่คำนึงถึงประเภท นอกจากนี้ยังใช้ได้กับ Spring MVC
ACV

1
@ACV คุณพูดถูกมันทำงานได้ดีมาก แต่สำหรับแอปที่ต้องอยู่ให้ทัน (เช่นแอป Spring MVC) ฉันคิดว่ามันไม่ใช่วิธีที่ดีในการทำเช่นนี้ ในกรณีของฉันฉันเคยใช้SpringApplication.exit(appContext, () -> returnCode).
Michael COLL

1
คุณหมายถึง VM ใดในบรรทัดสุดท้ายของคุณ หากคุณเริ่มต้นแอปพลิเคชัน Spring Boot ด้วยแสดงSpringApplication.run(MyApplication.class, args)ว่าไม่มีบริบทหลัก มีเพียงหนึ่งบริบทบริบทที่สร้างขึ้นและกลับมาโดยที่คุณแล้วทันทีrun close@ ไมเคิลพูดถูก สิ่งนี้จะใช้ไม่ได้กับโปรแกรมที่ต้องทำอะไรเลยหลังจากเริ่มต้นบริบท Spring ซึ่งเป็นโปรแกรมส่วนใหญ่
ผู้ช่วยให้รอด

@Savior JVM. มีบริบทผู้ปกครอง เรากำลังพูดถึงวิธีปิดแอปพลิเคชัน Spring boot โดยปกติคุณจะไม่ปิดเว็บแอปพลิเคชันด้วยวิธีนี้ ดังนั้นกลไกนี้มักจะใช้สำหรับแอปพลิเคชันอายุสั้นที่ทำบางอย่างแล้วต้องหยุด ตามค่าเริ่มต้น Spring boot จะยังคงทำงานต่อไปแม้ว่าคุณจะเสร็จสิ้นการประมวลผลแบทช์แล้วก็ตามดังนั้นคุณจึงต้องการใช้กลไกนี้
ACV

3

ในแอปพลิเคชันคุณสามารถSpringApplicationใช้ได้ นี้มีความคงที่exit()วิธีการที่จะใช้เวลาสองข้อโต้แย้งที่: ApplicationContextและExitCodeGenerator:

กล่าวคือคุณสามารถประกาศวิธีนี้:

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

ในการทดสอบการบูรณาการคุณสามารถทำได้โดยการเพิ่ม@DirtiesContextคำอธิบายประกอบในระดับชั้นเรียน:

  • @DirtiesContext(classMode=ClassMode.AFTER_CLASS) - ApplicationContext ที่เกี่ยวข้องจะถูกทำเครื่องหมายว่าสกปรกหลังจากคลาสทดสอบ
  • @DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) - ApplicationContext ที่เกี่ยวข้องจะถูกทำเครื่องหมายว่าสกปรกหลังจากแต่ละวิธีการทดสอบในคลาส

กล่าวคือ

@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 {
...

ตกลง. ฉันจะรับ ExecutorServiceExitCodeGenerator ได้ที่ไหน ถ้าเป็นถั่วคุณสามารถแสดงโค้ดตัวอย่างการสร้างได้หรือไม่ (และสร้างจากคลาสใด) ควรใส่เมธอด shutDown (ExecutorServiceExitCodeGenerator exitCodeGenerator) ในคลาสใด
Vlad G.

2

สิ่งนี้จะทำให้แน่ใจว่าแอปพลิเคชัน SpringBoot ปิดอย่างถูกต้องและทรัพยากรจะถูกปล่อยกลับสู่ระบบปฏิบัติการ

@Autowired
private ApplicationContext context;

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

    int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
    System.exit(exitCode);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.