Uruchamianie kodu po uruchomieniu Spring Boot

211

Chcę uruchomić kod po tym, jak moja wiosenna aplikacja uruchomi monitorowanie katalogu pod kątem zmian.

Próbowałem uruchomić nowy wątek, ale @Autowiredusługi nie zostały ustawione w tym momencie.

Udało mi się znaleźć ApplicationPreparedEvent, który odpala przed ustawieniem @Autowiredadnotacji. Idealnie byłoby, gdyby zdarzenie zostało uruchomione, gdy aplikacja będzie gotowa do przetwarzania żądań HTTP.

Czy istnieje lepsze zdarzenie do użycia lub lepszy sposób uruchamiania kodu po uruchomieniu aplikacji w trybie rozruchu wiosennego ?

potwory
źródło
Spring boot udostępnia dwa interfejsy ApplicationRunner i CommandLineRunner, których można użyć, gdy chcesz uruchomić kod po uruchomieniu rozruchu wiosennego. Możesz zapoznać się z tym artykułem na przykład realizacji - jhooq.com/applicationrunner-spring-boot
Rahul

Odpowiedzi:

121

Próbować:

@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
źródło
6
nie działa to podczas wdrażania aplikacji jako pliku war do zewnętrznego tomcat. Działa tylko z osadzonym kocurem
Saurabh
Nie, to nie działa. Ale w tym przypadku użycia lubię bardziej wyraźny sposób @Component. Zobacz odpowiedź z @cjstehno, aby uzyskać działanie w pliku wojny.
Anton Bessonov
320

Jest to tak proste:

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

Testowane na wersji 1.5.1.RELEASE

cahen
źródło
7
dzięki Ci. dzięki temu mój kod działał bez żadnych zmian. Jeszcze raz dziękuję za tak prostą odpowiedź. Będzie to również działać bez problemu z adnotacją @RequestMapping.
Harshit,
16
Ktoś może również chcieć użyć @EventListener(ContextRefreshedEvent.class)zamiast tego, który jest uruchamiany po utworzeniu komponentu bean, ale przed uruchomieniem serwera. Można go używać do wykonywania działań, zanim jakiekolwiek żądania trafią na serwer.
neeraj
3
@neeraj, pytanie dotyczy uruchomienia kodu po uruchomieniu Spring Boot. Jeśli go użyjesz ContextRefreshedEvent, będzie działał również po każdym odświeżeniu.
cahen
4
testowany na Spring boot 2.0.5. RELEASE
ritesh
2
Testowane w wersji 2.2.2. działa idealnie. to rozwiązanie oszczędza mój czas.
Arphile
96

Czy próbowałeś 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;
  }
}

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

Oto, co dokumentacja wspomina o zdarzeniach uruchamiania:

...

Zdarzenia aplikacji są wysyłane w następującej kolejności, w miarę działania aplikacji:

ApplicationStartedEvent jest wysyłany na początku uruchomienia, ale przed jakimkolwiek przetwarzaniem, z wyjątkiem rejestracji detektorów i inicjatorów.

ApplicationEnvironmentPreparedEvent jest wysyłany, gdy znane jest środowisko do użycia w kontekście, ale przed utworzeniem kontekstu.

ApplicationPreparedEvent jest wysyłany tuż przed rozpoczęciem odświeżania, ale po załadowaniu definicji komponentu bean.

ApplicationReadyEvent jest wysyłany po odświeżeniu i wszelkich powiązanych wywołaniach zwrotnych, aby wskazać, że aplikacja jest gotowa do obsługi żądań.

ApplicationFailedEvent jest wysyłany, jeśli istnieje wyjątek podczas uruchamiania.

...

raspacorp
źródło
11
Alternatywnie możesz to zrobić za pomocą @EventListeneradnotacji w metodzie Bean, przekazując jako argument zdarzenie klasy, do którego chcesz się podłączyć.
padilo 20.04.17
2
To powinna być wybrana odpowiedź.
varun113
2
Zmieniło się to w wersji Spring-boot 2. Jeśli przeprowadzasz portowanie z wersji 1.x i używasz ApplicationStartedEvent, teraz zamiast tego chcesz ApplicationStartingEvent.
Andy Brown,
Działa to absolutnie dobrze i myślę, że najlepiej to zrobić.
AVINASH SHRIMALI,
jesteś najlepszy
ancm 21.01.19
83

Dlaczego nie stworzyć fasoli, która uruchamia monitor podczas inicjalizacji, na przykład:

@Component
public class Monitor {
    @Autowired private SomeService service

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

initmetoda nie zostanie wywołana dopóki każdy autowiring odbywa się na fasoli.

cjstehno
źródło
14
Czasami @PostConstructstrzela zbyt wcześnie. Na przykład podczas korzystania z usługi Spring Cloud Stream Kafka @PostConstructuruchamia się, zanim aplikacja połączy się z Kafka. Rozwiązanie Dave'a Syera jest lepsze, ponieważ uruchamia się w odpowiednim czasie.
Elnur Abdurrakhimov
9
@PostConstructdzieje się podczas inicjalizacji, a nie później. Chociaż może to być przydatne w niektórych przypadkach, nie jest to poprawna odpowiedź, jeśli chcesz uruchomić po uruchomieniu Spring Boot. Na przykład chociaż @PostConstructnie kończy się, żaden z punktów końcowych nie jest dostępny.
cahen
63

„Spring Boot” polega na użyciu CommandLineRunner. Po prostu dodaj fasolę tego typu i możesz zacząć. W Spring 4.1 (Boot 1.2) jest też taki, SmartInitializingBeanktóry odbiera oddzwonienie po zainicjowaniu wszystkiego. I jest SmartLifecycle(od wiosny 3).

Dave Syer
źródło
Jakiś przykład tego? Czy można uruchomić komponent bean po uruchomieniu aplikacji za pomocą wiersza polecenia w dowolnym momencie?
Emilio
5
Nie wiem, co rozumiesz przez „dowolny moment”. Podręcznik użytkownika Spring Boot i przykłady zawierają przykłady użycia CommandLineRunner(i nowszych ApplicationRunner): docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… .
Dave Syer
Odkryłem, że Lifecycle jest preferowaną opcją wykonywania zadań asynchronicznych na etapach uruchamiania / zatrzymywania aplikacji, i próbuję dostrzec inne różnice między CommandLineRunner a InitializingBeans, ale nie mogę nic na ten temat znaleźć.
saljuama
3
kilka zwykłego przykładowego kodu użyciaCommandLineRunner
Aleksiej Szymon
41

Możesz rozszerzyć klasę za pomocą ApplicationRunner, przesłonić run()metodę i dodać tam kod.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

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

        //code goes here

    }
}
Gimhani
źródło
Idealny w wiosennych butach. Ale metoda run () została wywołana dwukrotnie, gdy ma ApplicationScope dla klasy. Tak więc metoda PostConstruct z powyższym działała lepiej.
Sam
26

ApplicationReadyEventjest naprawdę przydatny tylko wtedy, gdy zadanie, które chcesz wykonać, nie jest wymagane do poprawnego działania serwera. Dobrym przykładem jest uruchomienie zadania asynchronicznego w celu monitorowania czegoś pod kątem zmian.

Jeśli jednak serwer jest w stanie „niegotowym”, dopóki zadanie nie zostanie zakończone, lepiej go zaimplementować, SmartInitializingSingletonponieważ otrzymasz wywołanie zwrotne przed otwarciem portu REST i otwarciem serwera dla firmy.

Nie daj się skusić do @PostConstructwykonywania zadań, które powinny się zdarzyć tylko raz. Otrzymasz niegrzeczną niespodziankę, gdy zauważysz, że jest wywoływana wiele razy ...

Andy Brown
źródło
To powinna być wybrana odpowiedź. Jak wskazuje @Andy, SmartInitializingSingleton jest wywoływany tuż przed otwarciem portów.
Srikanth
24

W konfiguracji sprężynowej:

@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
źródło
12

Użyj SmartInitializingSingletonfasoli na wiosnę> 4.1

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

}

Alternatywnie CommandLineRunnermożna zaimplementować fasolę lub dodać do niej metodę fasoli @PostConstruct.

Jeff
źródło
Czy mogę wymagać zależności Autowired w tej metodzie? Chciałbym ustawić Profile
LppEdd
7

Podając przykład odpowiedzi Dave'a Syera, która działała jak urok:

@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
źródło
7

Wypróbuj ten, a uruchomi Twój kod, gdy kontekst aplikacji zostanie w pełni uruchomiony.

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent arg0) {
                // EXECUTE YOUR CODE HERE 
    }
}
Kalifornium
źródło
6

Bardzo podoba mi się sugestia użycia EventListeneradnotacji przez @cahen ( https://stackoverflow.com/a/44923402/9122660 ), ponieważ jest bardzo czysta. Niestety nie udało mi się uruchomić tego w konfiguracji Spring + Kotlin. To, co działa dla Kotlin, to dodanie klasy jako parametru metody:

@EventListener 
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
    System.out.println("hello world, I have just started up");
}
Ostecke
źródło
Umieść go w klasie aplikacji rozruchu wiosennego nie losowo@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
Ahmed na
nie musisz umieszczać go w klasie @SpringBootApplication. zrobi to każda klasa konfiguracji
George Marin
5

Najlepszym sposobem na wykonanie bloku kodu po uruchomieniu aplikacji Spring Boot jest skorzystanie z adnotacji PostConstruct lub do tego samego można użyć programu uruchamiającego z wiersza poleceń.

1. Korzystanie z adnotacji PostConstruct

@Configuration
public class InitialDataConfiguration {

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

}

2. Korzystanie z komponentu bean runner z wiersza poleceń

@Configuration
public class InitialDataConfiguration {

    @Bean
    CommandLineRunner runner() {
        return args -> {
            System.out.println("CommandLineRunner running in the UnsplashApplication class...");
        };
    }
}
Naresh Bhadke
źródło
3

wystarczy zaimplementować CommandLineRunner dla aplikacji rozruchu wiosennego. Musisz zaimplementować metodę uruchamiania,

public classs SpringBootApplication implements CommandLineRunner{

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

        }
}
prasad kp
źródło
0

Najlepszy sposób korzystania z CommandLineRunner lub ApplicationRunner Jedyną różnicą jest metoda run () CommandLineRunner akceptuje tablicę ciągów, a ApplicationRunner akceptuje ApplicationArugument.

Rushi Vanga
źródło