Ausführen von Code nach dem Start von Spring Boot

211

Ich möchte Code ausführen, nachdem meine Spring-Boot- App ein Verzeichnis auf Änderungen überwacht.

Ich habe versucht, einen neuen Thread auszuführen, aber die @AutowiredDienste wurden zu diesem Zeitpunkt noch nicht festgelegt.

Ich konnte herausfinden ApplicationPreparedEvent, welche Brände @Autowiredausgelöst werden, bevor die Anmerkungen gesetzt werden. Idealerweise möchte ich, dass das Ereignis ausgelöst wird, sobald die Anwendung bereit ist, http-Anforderungen zu verarbeiten.

Gibt es ein besseres Ereignis oder eine bessere Möglichkeit, Code auszuführen, nachdem die Anwendung im Spring-Boot live ist ?

Eintöpfe
quelle
Spring Boot bietet zwei Schnittstellen, ApplicationRunner und CommandLineRunner, die verwendet werden können, wenn Sie den Code nach dem Start des Spring Boot ausführen möchten. Ein Implementierungsbeispiel finden Sie in diesem Artikel - jhooq.com/applicationrunner-spring-boot
Rahul Wagh

Antworten:

121

Versuchen:

@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
quelle
6
Dies funktioniert nicht, wenn Sie eine Anwendung als War-Datei auf einem externen Tomcat bereitstellen. Es funktioniert nur mit eingebettetem Kater
Saurabh
Nein, es funktioniert nicht. Aber in diesem Anwendungsfall mag ich expliziter statt @Component. Siehe Antwort von @cjstehno, damit es in einer Kriegsdatei funktioniert.
Anton Bessonov
320

So einfach ist das:

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

Auf Version getestet 1.5.1.RELEASE

cahen
quelle
7
Danke. Dadurch funktionierte mein Code, ohne dass Änderungen erforderlich waren. Nochmals vielen Dank für eine so einfache Antwort. Dies funktioniert auch problemlos mit der Annotation @RequestMapping.
Harshit
16
Möglicherweise möchte jemand @EventListener(ContextRefreshedEvent.class)stattdessen stattdessen verwenden, was nach der Bean-Erstellung, jedoch vor dem Start des Servers ausgelöst wird. Es kann verwendet werden, um Aktivitäten auszuführen, bevor Anforderungen den Server erreichen.
Neeraj
3
@neeraj, die Frage betrifft das Ausführen von Code nach dem Start von Spring Boot. Wenn Sie verwenden ContextRefreshedEvent, wird es auch nach jeder Aktualisierung ausgeführt.
Cahen
4
getestet auf Spring Boot 2.0.5.RELEASE
Ritesh
2
Getestet am 2.2.2 Release. es funktioniert perfekt. Diese Lösung spart mir Zeit.
Arphile
96

Haben Sie ApplicationReadyEvent ausprobiert?

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

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

In der Dokumentation wird Folgendes zu den Startereignissen erwähnt:

...

Anwendungsereignisse werden in der folgenden Reihenfolge gesendet, während Ihre Anwendung ausgeführt wird:

Ein ApplicationStartedEvent wird zu Beginn eines Laufs gesendet, jedoch vor jeder Verarbeitung mit Ausnahme der Registrierung von Listenern und Initialisierern.

Ein ApplicationEnvironmentPreparedEvent wird gesendet, wenn die im Kontext zu verwendende Umgebung bekannt ist, jedoch bevor der Kontext erstellt wird.

Ein ApplicationPreparedEvent wird unmittelbar vor dem Start der Aktualisierung gesendet, jedoch nachdem die Bean-Definitionen geladen wurden.

Nach der Aktualisierung wird ein ApplicationReadyEvent gesendet, und alle zugehörigen Rückrufe wurden verarbeitet, um anzuzeigen, dass die Anwendung für Serviceanforderungen bereit ist.

Ein ApplicationFailedEvent wird gesendet, wenn beim Start eine Ausnahme auftritt.

...

raspacorp
quelle
11
Alternativ können Sie dies mithilfe von @EventListenerAnmerkungen zu einer Bean-Methode tun und das Klassenereignis, an das Sie sich anschließen möchten, als Argument übergeben.
Padilo
2
Dies sollte die gewählte Antwort sein.
Varun113
2
Dies hat sich in Spring-Boot 2 geändert. Wenn Sie von 1.x portieren und ApplicationStartedEvent verwenden, möchten Sie jetzt stattdessen ApplicationStartingEvent.
Andy Brown
Das funktioniert absolut gut und ich denke, der beste Weg, dies zu tun.
AVINASH SHRIMALI
Sie sind der Beste
ancm
83

Warum erstellen Sie nicht einfach eine Bean, die Ihren Monitor bei der Initialisierung startet?

@Component
public class Monitor {
    @Autowired private SomeService service

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

Die initMethode wird erst aufgerufen, wenn für die Bean eine automatische Verdrahtung durchgeführt wurde.

cjstehno
quelle
14
Brennt manchmal @PostConstructzu früh. Wenn Sie beispielsweise Spring Cloud Stream Kafka verwenden, wird dies @PostConstructausgelöst, bevor die Anwendung an Kafka gebunden wird. Die Lösung von Dave Syer ist besser, weil sie rechtzeitig ausgelöst wird.
Elnur Abdurrakhimov
9
@PostConstructgeschieht während der Initialisierung, nicht danach. Obwohl dies in einigen Fällen nützlich sein kann, ist es nicht die richtige Antwort, wenn Sie nach dem Start von Spring Boot ausgeführt werden möchten . Beispielsweise ist @PostConstructkeiner der Endpunkte verfügbar , obwohl er nicht fertig ist.
Cahen
63

Der "Spring Boot" Weg ist die Verwendung von a CommandLineRunner. Fügen Sie einfach Bohnen dieser Art hinzu und schon kann es losgehen. In Spring 4.1 (Boot 1.2) gibt es auch einen, SmartInitializingBeander einen Rückruf erhält, nachdem alles initialisiert wurde. Und das gibt es SmartLifecycle(ab Frühling 3).

Dave Syer
quelle
Ein Beispiel dafür? Ist es möglich, eine Bean nach dem Ausführen der App in einem beliebigen Moment über die Befehlszeile auszuführen?
Emilio
5
Ich weiß nicht, was du mit "willkürlichem Moment" meinst. Das Spring Boot-Benutzerhandbuch und Beispiele enthalten Beispiele für die Verwendung eines CommandLineRunner(und des neueren ApplicationRunner): docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… .
Dave Syer
Ich habe festgestellt, dass Lifecycle die bevorzugte Option ist, um asynchrone Aufgaben in Start- / Stopp-Phasen der Anwendung auszuführen, und ich versuche, andere Unterschiede zwischen CommandLineRunner und InitializingBeans zu erkennen, kann jedoch nichts dazu finden.
Saljuama
3
Paar üblichen Beispiel Code der VerwendungCommandLineRunner
Alexey Simonov
41

Sie können eine Klasse mit erweitern ApplicationRunner, die run()Methode überschreiben und dort den Code hinzufügen.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

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

        //code goes here

    }
}
Gimhani
quelle
Perfekt im Frühlingsstiefel. Die run () -Methode wurde jedoch zweimal aufgerufen, wenn ApplicationScope für die Klasse vorhanden war. Die PostConstruct-Methode mit den oben genannten Methoden funktionierte also besser.
Sam
26

ApplicationReadyEventist wirklich nur dann nützlich, wenn die Aufgabe, die Sie ausführen möchten, keine Voraussetzung für einen korrekten Serverbetrieb ist. Ein gutes Beispiel ist das Starten einer asynchronen Aufgabe, um etwas auf Änderungen zu überwachen.

Wenn sich Ihr Server jedoch bis zum Abschluss der Aufgabe in einem Status "Nicht bereit" befindet, ist es besser, ihn zu implementieren, SmartInitializingSingletonda Sie den Rückruf erhalten, bevor Ihr REST-Port geöffnet wurde und Ihr Server für den Geschäftsbetrieb geöffnet ist.

Seien Sie nicht versucht, @PostConstructAufgaben zu verwenden, die nur einmal ausgeführt werden sollten. Sie werden eine grobe Überraschung bekommen, wenn Sie bemerken, dass es mehrmals aufgerufen wird ...

Andy Brown
quelle
Dies sollte die gewählte Antwort sein. Wie @Andy hervorhebt, wird SmartInitializingSingleton unmittelbar vor dem Öffnen der Ports aufgerufen.
Srikanth
24

Mit Federkonfiguration:

@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
quelle
12

Verwenden Sie SmartInitializingSingletonim Frühjahr eine Bohne> 4.1

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

}

Alternativ kann eine CommandLineRunnerBean implementiert oder eine Bean-Methode mit kommentiert werden @PostConstruct.

Jeff
quelle
Kann ich innerhalb dieser Methode eine Autowired-Abhängigkeit benötigen? Ich möchte Profile
LppEdd
7

Ein Beispiel für die Antwort von Dave Syer, die wie ein Zauber wirkte:

@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
quelle
7

Versuchen Sie dies und es wird Ihr Code ausgeführt, wenn der Anwendungskontext vollständig gestartet wurde.

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

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

Ich mag den Vorschlag für die Verwendung der EventListenerAnmerkung von @cahen ( https://stackoverflow.com/a/44923402/9122660 ) sehr, da sie sehr sauber ist. Leider konnte ich dies in einem Spring + Kotlin-Setup nicht zum Laufen bringen. Für Kotlin funktioniert das Hinzufügen der Klasse als Methodenparameter:

@EventListener 
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
    System.out.println("hello world, I have just started up");
}
Ostecke
quelle
Legen Sie es in die Spring Boot-Anwendungsklasse nicht zufällig außerhalb@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
Ahmed na
5

Der beste Weg, um einen Codeblock nach dem Start der Spring Boot-Anwendung auszuführen, ist die Verwendung der PostConstruct-Annotation. Oder Sie können auch den Befehlszeilen-Runner für dieselbe verwenden.

1. Verwenden der PostConstruct-Annotation

@Configuration
public class InitialDataConfiguration {

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

}

2. Verwenden der Befehlszeilen-Runner-Bean

@Configuration
public class InitialDataConfiguration {

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

Implementieren Sie einfach CommandLineRunner für die Spring-Boot-Anwendung. Sie müssen die Ausführungsmethode implementieren.

public classs SpringBootApplication implements CommandLineRunner{

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

        }
}
prasad kp
quelle
0

Beste Verwendung von CommandLineRunner oder ApplicationRunner Der einzige Unterschied zwischen der run () -Methode CommandLineRunner akzeptiert ein Array von Zeichenfolgen und ApplicationRunner akzeptiert ApplicationArugument.

Rushi Vanga
quelle