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 ?



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

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


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.

...


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.


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


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

    }
}

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


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");
  }
}

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.


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

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

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");
}

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...");
        };
    }
}

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 

        }
}

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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.