Ejecución de código después de que comience Spring Boot


211

Quiero ejecutar el código después de que mi aplicación spring-boot comience a monitorear un directorio en busca de cambios.

He intentado ejecutar un nuevo hilo pero los @Autowiredservicios no se han establecido en ese punto.

He podido encontrar ApplicationPreparedEvent, que se dispara antes de que @Autowiredse establezcan las anotaciones. Idealmente, me gustaría que el evento se active una vez que la aplicación esté lista para procesar solicitudes http.

¿Hay un mejor evento para usar, o una mejor manera de ejecutar el código después de que la aplicación esté activa en spring-boot ?



Spring boot proporciona dos interfaces, ApplicationRunner y CommandLineRunner, que se pueden usar cuando desea ejecutar el código después de que se inicia el inicio de Spring. Puede consultar este artículo para ver un ejemplo de implementación: jhooq.com/applicationrunner-spring-boot
Rahul Wagh

Respuestas:


121

Tratar:

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

66
esto no funciona cuando implementa la aplicación como archivo war en un tomcat externo. Funciona solo con tomcat incrustado
Saurabh

No, no funciona Pero en este caso de uso, me gusta la forma más explícita en lugar de @Component. Vea la respuesta de @cjstehno para que funcione en un archivo de guerra.
Anton Bessonov

322

Es tan simple como esto:

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

Probado en la versión 1.5.1.RELEASE


77
gracias. Esto hizo que mi código funcionara sin ningún cambio requerido. Gracias de nuevo por una respuesta tan simple. Esto también funcionará con la anotación @RequestMapping sin ningún problema.
Harshit

16
Alguien también puede desear usarlo @EventListener(ContextRefreshedEvent.class), que se activa después de la creación del bean, pero antes de que se inicie el servidor. Se puede usar para realizar actividades antes de que cualquier solicitud llegue al servidor.
neeraj

3
@neeraj, la pregunta es sobre la ejecución del código después de que se inicie Spring Boot. Si lo usa ContextRefreshedEvent, también se ejecutará después de cada actualización.
cahen

44
probado en Spring boot 2.0.5
PUBLICACIÓN

2
Probado en la versión 2.2.2. Funciona perfectamente. Esta solución me ahorra tiempo.
Arphile

96

¿Has probado 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;
  }
}

Código de: http://blog.netgloo.com/2014/11/13/run-code-at-spring-boot-startup/

Esto es lo que menciona la documentación sobre los eventos de inicio:

...

Los eventos de la aplicación se envían en el siguiente orden, a medida que se ejecuta la aplicación:

Un ApplicationStartedEvent se envía al comienzo de una ejecución, pero antes de cualquier procesamiento, excepto el registro de oyentes e inicializadores.

Un ApplicationEnvironmentPreparedEvent se envía cuando se conoce el entorno que se utilizará en el contexto, pero antes de que se cree el contexto.

Se envía un ApplicationPreparedEvent justo antes de que se inicie la actualización, pero después de que se hayan cargado las definiciones de bean.

Se envía un ApplicationReadyEvent después de la actualización y se han procesado las devoluciones de llamada relacionadas para indicar que la aplicación está lista para atender las solicitudes.

Se envía un ApplicationFailedEvent si hay una excepción al inicio.

...


11
Como alternativa, puede hacerlo utilizando @EventListeneranotaciones en un método Bean, pasando como argumento el evento de clase al que desea conectarse.
padilo

2
Esta debería ser la respuesta elegida.
varun113

2
Esto ha cambiado en spring-boot 2. Si está portando desde 1.xy estaba usando ApplicationStartedEvent, entonces ahora quiere ApplicationStartingEvent en su lugar.
Andy Brown el

Esto funciona absolutamente bien y creo que es la mejor manera de hacerlo.
AVINASH SHRIMALI

eres el mejor
ancm

83

¿Por qué no simplemente crear un bean que inicia su monitor en la inicialización, algo como:

@Component
public class Monitor {
    @Autowired private SomeService service

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

el initmétodo no se llamará hasta que se realice un cableado automático para el bean.


14
A veces @PostConstructdispara demasiado temprano. Por ejemplo, cuando se usa Spring Cloud Stream Kafka, se @PostConstructdispara antes de que la aplicación se una a Kafka. La solución de Dave Syer es mejor porque se dispara a tiempo.
Elnur Abdurrakhimov

9
@PostConstructsucede durante la inicialización, no después. Aunque esto puede ser útil en algunos casos, no es la respuesta correcta si desea ejecutar después del inicio de Spring Boot. Por ejemplo, mientras @PostConstructno termina, ninguno de los puntos finales está disponible.
cahen

63

La forma de "Spring Boot" es usar a CommandLineRunner. Solo agregue frijoles de ese tipo y estará listo. En Spring 4.1 (Boot 1.2) también hay un SmartInitializingBeanque recibe una devolución de llamada después de que todo se haya inicializado. Y la hay SmartLifecycle(desde la primavera 3).


¿Algún ejemplo de eso? ¿Es posible ejecutar un bean después de que la aplicación se esté ejecutando, a través de la línea de comandos en un momento arbitrario?
Emilio

55
No sé a qué te refieres con "momento arbitrario". La guía del usuario y los ejemplos de Spring Boot tienen ejemplos del uso de CommandLineRunner(y el más reciente ApplicationRunner): docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/… .
Dave Syer

Descubrí que Lifecycle es la opción preferida para realizar tareas asincrónicas en las etapas de inicio / detención de la aplicación, y estoy tratando de detectar otras diferencias entre CommandLineRunner y InitializingBeans, pero no puedo encontrar nada al respecto.
Saljuama

3
par código de ejemplo habitual de usoCommandLineRunner
Alexey Simonov

41

Puede extender una clase usando ApplicationRunner, anular el run()método y agregar el código allí.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

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

        //code goes here

    }
}

Perfecto en Spring Boot. Pero el método run () se llamó dos veces al tener ApplicationScope para la clase. Entonces, el método PostConstruct con lo anterior funcionó mejor.
Sam

26

ApplicationReadyEventen realidad solo es útil si la tarea que desea realizar no es un requisito para el correcto funcionamiento del servidor. Iniciar una tarea asincrónica para monitorear algo en busca de cambios es un buen ejemplo.

Sin embargo, si su servidor está en un estado 'no listo' hasta que se complete la tarea, entonces es mejor implementarlo SmartInitializingSingletonporque recibirá la devolución de llamada antes de que su puerto REST se haya abierto y su servidor esté abierto para los negocios.

No caigas en la tentación de utilizarlo @PostConstructpara tareas que solo deberían ocurrir una vez. Obtendrá una sorpresa grosera cuando note que se llama varias veces ...


Esta debería ser la respuesta elegida. Como señala @Andy, se llama a SmartInitializingSingleton justo antes de que se abran los puertos.
Srikanth

25

Con configuración de resorte:

@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

Usa un SmartInitializingSingletonfrijol en primavera> 4.1

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

}

Como alternativa, CommandLineRunnerse puede implementar un bean o anotar un método de bean con @PostConstruct.


¿Puedo requerir una dependencia de Autowired dentro de ese método? Me gustaría establecer perfiles
LppEdd

7

Proporcionando un ejemplo para la respuesta de Dave Syer, que funcionó a las mil maravillas:

@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

Pruebe este y ejecutará su código cuando el contexto de la aplicación se haya iniciado por completo.

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

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

6

Realmente me gusta la sugerencia para el uso de la EventListeneranotación por @cahen ( https://stackoverflow.com/a/44923402/9122660 ) ya que está muy limpia. Lamentablemente, no pude hacer que esto funcionara en una configuración Spring + Kotlin. Lo que sí funciona para Kotlin es agregar la clase como parámetro de método:

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

Póngalo en la clase de aplicación de arranque de primavera no al azar fuera@SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
Ahmed na

no necesita ponerlo a la clase @SpringBootApplication. cualquier clase de configuración servirá
George Marin

5

La mejor manera de ejecutar el bloque de código después de que se inicie la aplicación Spring Boot es usar la anotación PostConstruct, o también puede usar el corredor de línea de comando para el mismo.

1. Usando la anotación PostConstruct

@Configuration
public class InitialDataConfiguration {

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

}

2. Usando la línea de comando bean runner

@Configuration
public class InitialDataConfiguration {

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

3

simplemente implemente CommandLineRunner para la aplicación de arranque de primavera. Necesita implementar el método de ejecución,

public classs SpringBootApplication implements CommandLineRunner{

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

        }
}

0

La mejor manera de usar CommandLineRunner o ApplicationRunner La única diferencia entre el método run () CommandLineRunner acepta una matriz de cadenas y ApplicationRunner acepta ApplicationArugument.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.