Menjalankan kode setelah Spring Boot dimulai


211

Saya ingin menjalankan kode setelah aplikasi spring-boot saya mulai memantau direktori untuk perubahan.

Saya telah mencoba menjalankan utas baru tetapi @Autowiredlayanan belum ditetapkan pada saat itu.

Saya sudah bisa menemukan ApplicationPreparedEvent, mana yang menyala sebelum @Autowiredanotasi diatur. Idealnya saya ingin acara memecat setelah aplikasi siap untuk memproses permintaan http.

Apakah ada acara yang lebih baik untuk digunakan, atau cara yang lebih baik untuk menjalankan kode setelah aplikasi hidup di musim semi-boot ?



Spring boot menyediakan dua antarmuka ApplicationRunner dan CommandLineRunner yang dapat digunakan ketika Anda ingin menjalankan kode setelah boot spring dimulai. Anda bisa merujuk ke artikel ini untuk contoh implementasi - jhooq.com/applicationrunner-spring-boot
Rahul Wagh

Jawaban:


121

Mencoba:

@Configuration
@EnableAutoConfiguration
@ComponentScan
public class Application extends SpringBootServletInitializer {

    @SuppressWarnings("resource")
    public static void main(final String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);

        context.getBean(Table.class).fillWithTestdata(); // <-- here
    }
}

6
ini tidak berfungsi ketika Anda menggunakan aplikasi sebagai file perang ke kucing jantan eksternal. Ini hanya berfungsi dengan tomcat tertanam
Saurabh

Tidak, itu tidak berhasil. Tetapi dalam hal ini saya suka cara yang lebih eksplisit daripada @Component. Lihat jawaban dari @cjstehno untuk membuatnya berfungsi dalam file perang.
Anton Bessonov

322

Sesederhana ini:

@EventListener(ApplicationReadyEvent.class)
public void doSomethingAfterStartup() {
    System.out.println("hello world, I have just started up");
}

Diuji pada versi 1.5.1.RELEASE


7
terimakasih. ini membuat kode saya berfungsi tanpa ada perubahan yang diperlukan. Sekali lagi terima kasih atas jawaban yang sederhana. Ini juga akan berfungsi dengan anotasi @RequestMapping tanpa masalah.
Harshit

16
Seseorang mungkin juga ingin menggunakan @EventListener(ContextRefreshedEvent.class), yang dipicu setelah pembuatan kacang, tetapi sebelum server dimulai. Itu dapat digunakan untuk melakukan aktivitas sebelum permintaan apapun mengenai server.
neeraj

3
@neeraj, pertanyaannya adalah tentang menjalankan kode setelah Boot Musim Semi dimulai. Jika Anda menggunakan ContextRefreshedEvent, itu akan berjalan setelah setiap penyegaran juga.
cahen

4
diuji pada Spring boot 2.0.5.RELEASE
ritesh

2
Diuji pada rilis 2.2.2. ini bekerja dengan sempurna. solusi ini menghemat waktu saya.
Arphile

96

Sudahkah Anda mencoba ApplicationReadyEvent?

@Component
public class ApplicationStartup 
implements ApplicationListener<ApplicationReadyEvent> {

  /**
   * This event is executed as late as conceivably possible to indicate that 
   * the application is ready to service requests.
   */
  @Override
  public void onApplicationEvent(final ApplicationReadyEvent event) {

    // here your code ...

    return;
  }
}

Kode dari: http://blog.netgloo.com/2014/11/13/run-code-at-spring-boot-startup/

Inilah yang disebutkan dalam dokumentasi tentang acara startup:

...

Acara aplikasi dikirim dalam urutan berikut, saat aplikasi Anda berjalan:

ApplicationStartedEvent dikirim pada awal menjalankan, tetapi sebelum pemrosesan apa pun kecuali pendaftaran pendengar dan inisialisasi.

ApplicationEnvironmentPreparedEvent dikirim ketika Lingkungan yang akan digunakan dalam konteks diketahui, tetapi sebelum konteks dibuat.

ApplicationPreparedEvent dikirim tepat sebelum refresh dimulai, tetapi setelah definisi kacang dimuat.

ApplicationReadyEvent dikirim setelah penyegaran dan setiap panggilan balik terkait telah diproses untuk menunjukkan bahwa aplikasi siap untuk melayani permintaan.

ApplicationFailedEvent dikirim jika ada pengecualian saat startup.

...


11
Sebagai alternatif, Anda bisa melakukan ini dengan menggunakan @EventListeneranotasi pada metode Bean, dengan argumen sebagai peristiwa kelas yang ingin Anda kaitkan.
padilo

2
Ini harus menjadi jawaban yang dipilih.
varun113

2
Ini telah berubah di musim semi-boot 2. Jika Anda porting dari 1.x dan menggunakan ApplicationStartedEvent maka Anda sekarang ingin ApplicationStartingEvent sebagai gantinya.
Andy Brown

Ini berfungsi dengan sangat baik dan saya pikir cara terbaik untuk melakukannya.
AVINASH SHRIMALI

Anda adalah yang terbaik
ancm

83

Mengapa tidak membuat kacang yang memulai monitor Anda saat inisialisasi, seperti:

@Component
public class Monitor {
    @Autowired private SomeService service

    @PostConstruct
    public void init(){
        // start your monitoring in here
    }
}

yang initmetode tidak akan dipanggil sampai autowiring apapun dilakukan untuk kacang.


14
Terkadang @PostConstructkebakaran terlalu dini. Misalnya, saat menggunakan Spring Cloud Stream Kafka, @PostConstructapi sebelum aplikasi berikatan dengan Kafka. Solusi Dave Syer lebih baik karena kebakaran tepat waktu.
Elnur Abdurrakhimov

9
@PostConstructterjadi selama inisialisasi, bukan setelah. Meskipun ini dapat berguna dalam beberapa kasus, itu bukan jawaban yang benar jika Anda ingin menjalankan setelah Boot Spring dimulai. Misalnya, sementara @PostConstructtidak selesai, tidak ada titik akhir yang tersedia.
cahen

63

Cara "Spring Boot" adalah dengan menggunakan a CommandLineRunner. Cukup tambahkan kacang jenis itu dan Anda siap melakukannya. Di Spring 4.1 (Boot 1.2) ada juga SmartInitializingBeanyang mendapat panggilan balik setelah semuanya diinisialisasi. Dan ada SmartLifecycle(dari Spring 3).


Adakah contohnya? Apakah mungkin untuk mengeksekusi kacang setelah aplikasi berjalan, melalui baris perintah di saat yang sewenang-wenang?
Emilio

5
Tidak tahu apa yang Anda maksud dengan "momen sewenang-wenang". Panduan pengguna dan sampel Spring Boot memiliki contoh penggunaan CommandLineRunner(dan yang lebih baru ApplicationRunner): docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… .
Dave Syer

Saya menemukan, bahwa Lifecycle adalah pilihan yang lebih disukai untuk melakukan tugas-tugas asinkron pada tahap awal / berhenti aplikasi, dan saya mencoba untuk menemukan perbedaan lain antara CommandLineRunner dan InitializingBeans, tetapi tidak dapat menemukan apa pun tentang itu.
saljuama

3
beberapa contoh kode yang biasa digunakanCommandLineRunner
Alexey Simonov

41

Anda dapat memperluas kelas menggunakan ApplicationRunner, menimpa run()metode dan menambahkan kode di sana.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments applicationArguments) throws Exception {

        //code goes here

    }
}

Sempurna di Boot Musim Semi. Tetapi menjalankan () metode dipanggil dua kali ketika memiliki ApplicationScope untuk kelas. Jadi metode PostConstruct dengan cara di atas bekerja lebih baik.
Sam

26

ApplicationReadyEventbenar-benar hanya berguna jika tugas yang ingin Anda lakukan bukan persyaratan untuk operasi server yang benar. Memulai tugas async untuk memonitor sesuatu untuk perubahan adalah contoh yang baik.

Namun, jika server Anda dalam keadaan 'tidak siap' sampai tugas selesai maka lebih baik untuk diterapkan SmartInitializingSingletonkarena Anda akan mendapatkan panggilan balik sebelum port REST Anda dibuka dan server Anda terbuka untuk bisnis.

Jangan tergoda untuk menggunakan @PostConstructtugas yang seharusnya hanya terjadi sekali saja. Anda akan mendapatkan kejutan kasar ketika Anda melihatnya dipanggil beberapa kali ...


Ini harus menjadi jawaban yang dipilih. Seperti yang ditunjukkan oleh @Andy, SmartInitializingSingleton dipanggil tepat sebelum port dibuka.
Srikanth

25

Dengan konfigurasi pegas:

@Configuration
public class ProjectConfiguration {
    private static final Logger log = 
   LoggerFactory.getLogger(ProjectConfiguration.class);

   @EventListener(ApplicationReadyEvent.class)
   public void doSomethingAfterStartup() {
    log.info("hello world, I have just started up");
  }
}

12

Gunakan SmartInitializingSingletonkacang di musim semi> 4.1

@Bean
public SmartInitializingSingleton importProcessor() {
    return () -> {
        doStuff();
    };

}

Sebagai alternatif CommandLineRunnerkacang dapat diimplementasikan atau menjelaskan metode kacang dengan @PostConstruct.


Bisakah saya memerlukan ketergantungan Autowired di dalam metode itu? Saya ingin menetapkan Profil
LppEdd

7

Memberikan contoh untuk jawaban Dave Syer, yang bekerja seperti pesona:

@Component
public class CommandLineAppStartupRunner implements CommandLineRunner {
    private static final Logger logger = LoggerFactory.getLogger(CommandLineAppStartupRunner.class);

    @Override
    public void run(String...args) throws Exception {
        logger.info("Application started with command-line arguments: {} . \n To kill this application, press Ctrl + C.", Arrays.toString(args));
    }
}

7

Coba ini dan itu akan menjalankan kode Anda ketika konteks aplikasi sudah sepenuhnya dimulai.

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent arg0) {
                // EXECUTE YOUR CODE HERE 
    }
}

6

Saya sangat suka saran untuk penggunaan EventListeneranotasi oleh @cahen ( https://stackoverflow.com/a/44923402/9122660 ) karena sangat bersih. Sayangnya saya tidak bisa menjalankan ini dalam pengaturan Spring + Kotlin. Apa yang berfungsi untuk Kotlin adalah menambahkan kelas sebagai parameter metode:

@EventListener 
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
    System.out.println("hello world, I have just started up");
}

Letakkan di kelas aplikasi booting musim semi tidak secara acak@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
Ahmed na

Anda tidak perlu membuatnya perlu ke kelas @SpringBootApplication. kelas konfigurasi apa pun akan melakukannya
George Marin

5

Cara terbaik untuk mengeksekusi blok kode setelah aplikasi Boot Spring dimulai adalah menggunakan anotasi PostConstruct. Atau Anda juga dapat menggunakan command line runner untuk hal yang sama.

1. Menggunakan anotasi PostConstruct

@Configuration
public class InitialDataConfiguration {

    @PostConstruct
    public void postConstruct() {
        System.out.println("Started after Spring boot application !");
    }

}

2. Menggunakan kacang runner baris perintah

@Configuration
public class InitialDataConfiguration {

    @Bean
    CommandLineRunner runner() {
        return args -> {
            System.out.println("CommandLineRunner running in the UnsplashApplication class...");
        };
    }
}

3

cukup implementasikan CommandLineRunner untuk aplikasi boot spring. Anda perlu menerapkan metode jalankan,

public classs SpringBootApplication implements CommandLineRunner{

    @Override
        public void run(String... arg0) throws Exception {
        // write your logic here 

        }
}

0

Cara terbaik Anda menggunakan CommandLineRunner atau ApplicationRunner Satu-satunya perbedaan antara dijalankan () metode CommandLineRunner menerima array string dan ApplicationRunner menerima ApplicationArugument.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.