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 ?

pelayan
sumber
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
    }
}
Anton Bessonov
sumber
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

cahen
sumber
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.

...

raspacorp
sumber
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.

cjstehno
sumber
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).

Dave Syer
sumber
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

    }
}
Gimhani
sumber
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 ...

Andy Brown
sumber
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");
  }
}
freemanpolys
sumber
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.

Jeff
sumber
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));
    }
}
Paulo Pedroso
sumber
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 
    }
}
Kalifornium
sumber
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");
}
Ostecke
sumber
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...");
        };
    }
}
Naresh Bhadke
sumber
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 

        }
}
prasad kp
sumber
0

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

Rushi Vanga
sumber