441

I want to run code after my spring-boot app starts to monitor a directory for changes.

I have tried running a new thread but the @Autowired services have not been set at that point.

I have been able to find ApplicationPreparedEvent, which fires before the @Autowired annotations are set. Ideally I would like the event to fire once the application is ready to process http requests.

Is there a better event to use, or a better way of running code after the application is live in spring-boot?

1

20 Answers 20

712

It is as simple as this:

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

Tested on version 1.5.1.RELEASE

15
  • 15
    thanks you. this made my code work without any change required. Thanks again for such a simple answer. This will also work with @RequestMapping annotation without any problem.
    – Harshit
    Commented Jul 13, 2017 at 4:55
  • 78
    Someone may also wish to use @EventListener(ContextRefreshedEvent.class) instead, which gets triggered after bean creation, but before the server starts. It can be used to perform activities before any requests hit the server.
    – neeraj
    Commented Jan 22, 2018 at 7:38
  • 3
    does this class where you put event listener needs to be annotated with Component, Service etc. ? Commented Oct 16, 2018 at 7:58
  • 4
    tested on Spring boot 2.0.5.RELEASE
    – ritesh
    Commented Jul 31, 2019 at 11:13
  • 2
    Tested on 2.2.2 Release. it works perfectly. this solution saves my time.
    – Arphile
    Commented Jan 30, 2020 at 6:33
157

Try:

@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
    }
}
2
  • 25
    this does not work when you deploy application as war file to an external tomcat. It works only with embedded tomcat
    – Ben W
    Commented Mar 17, 2016 at 13:56
  • 1
    No, it doesn't work. But in this use case I like more explicit way instead of @Component. See answer from @cjstehno to get it work in a war file. Commented Jun 30, 2016 at 7:00
156

Have you tried 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;
  }
}

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

This is what the documentation mentions about the startup events:

...

Application events are sent in the following order, as your application runs:

An ApplicationStartedEvent is sent at the start of a run, but before any processing except the registration of listeners and initializers.

An ApplicationEnvironmentPreparedEvent is sent when the Environment to be used in the context is known, but before the context is created.

An ApplicationPreparedEvent is sent just before the refresh is started, but after bean definitions have been loaded.

An ApplicationReadyEvent is sent after the refresh and any related callbacks have been processed to indicate the application is ready to service requests.

An ApplicationFailedEvent is sent if there is an exception on startup.

...

2
  • 15
    As an alternative, you can do this using @EventListenerannotation on a Bean method, passing as argument the class event you want to hook to.
    – padilo
    Commented Apr 20, 2017 at 16:18
  • 3
    This has changed in spring-boot 2. If you are porting up from 1.x and were using ApplicationStartedEvent then you now want ApplicationStartingEvent instead.
    – Andy Brown
    Commented Aug 23, 2018 at 9:54
106

Why not just create a bean that starts your monitor on initialization, something like:

@Component
public class Monitor {
    @Autowired private SomeService service

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

the init method will not be called until any autowiring is done for the bean.

5
  • 25
    Sometimes @PostConstruct fires too early. For example, when using Spring Cloud Stream Kafka, @PostConstruct fires before application binds to Kafka. Dave Syer's solution is better because it fires timely. Commented Apr 23, 2017 at 4:04
  • 17
    @PostConstruct happens during the initialisation, not after. Although this can be useful in some cases, it's not the correct answer if you want to run after Spring Boot starts. For example, while @PostConstruct doesn't finish, none of the endpoints are available.
    – cahen
    Commented Jul 5, 2017 at 10:00
  • 1
    Not quite per the OP question. at @PostConstruct, this bean is constructed, like beans in this class scope is autowired, etc. but the application as a whole may not be ready, for instance, other beans may still in the process of injection or wiring.
    – TGU
    Commented Jan 12, 2021 at 14:31
  • If you do anything long-running in the @PostConstruct (such as HTTP requests with retry backoffs), you won't get great behavior because sending SIGTERM doesn't interrupt the thread running the @PostConstruct, so your app refuses to shutdown until that method exits.
    – Shannon
    Commented Sep 27, 2021 at 23:25
  • In multithreading world, there is a chance that @PostConstruct may cause thread blocking, If your task is running for a long hours. Commented Dec 6, 2022 at 18:35
76

The "Spring Boot" way is to use a CommandLineRunner. Just add beans of that type and you are good to go. In Spring 4.1 (Boot 1.2) there is also a SmartInitializingBean which gets a callback after everything has initialized. And there is SmartLifecycle (from Spring 3).

5
  • Any example of that? Is it possible to execute a bean after app is running, via command line in an arbitrary moment?
    – Emilio
    Commented Sep 21, 2015 at 11:27
  • 7
    Don't know what you mean by "arbitrary moment". The Spring Boot user guide and samples have examples of using a CommandLineRunner (and the newer ApplicationRunner): docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/….
    – Dave Syer
    Commented Sep 24, 2015 at 7:00
  • I found, that Lifecycle is the prefered option to perform asynchronous tasks on start/stop stages of the application, and I'm trying to spot other differences between the CommandLineRunner and the InitializingBeans, but can't find anything about that.
    – saljuama
    Commented Nov 28, 2015 at 13:30
  • 4
    couple usual example code of using CommandLineRunner Commented Apr 4, 2018 at 9:56
  • Why is it better than @EventListener(ApplicationReadyEvent.class), if you don't need access to command line arguments? Commented Nov 10, 2021 at 13:08
54

ApplicationReadyEvent is really only useful if the task you want to perform is not a requirement for correct server operation. Starting an async task to monitor something for changes is a good example.

If, however your server is in a 'not ready' state until the task is completed then it's better to implement SmartInitializingSingleton because you'll get the callback before your REST port has been opened and your server is open for business.

Don't be tempted to use @PostConstruct for tasks that should only happen once ever. You'll get a rude surprise when you notice it being called multiple times...

1
  • This should be the chosen answer. As @Andy points out, SmartInitializingSingleton is called just before the ports are opened.
    – Srikanth
    Commented Mar 19, 2018 at 17:56
44

You can extend a class using ApplicationRunner , override the run() method and add the code there.

import org.springframework.boot.ApplicationRunner;

@Component
public class ServerInitializer implements ApplicationRunner {

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

        //code goes here

    }
}
1
  • Perfect in Spring Boot. But run() method was called twice when having ApplicationScope for the class. So PostConstruct method with the above worked better.
    – sam
    Commented Oct 11, 2018 at 7:56
16

Best way to execute block of code after Spring Boot application started is using PostConstruct annotation.Or also you can use command line runner for the same.

1. Using PostConstruct annotation

@Configuration
public class InitialDataConfiguration {

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

}

2. Using command line runner bean

@Configuration
public class InitialDataConfiguration {

    @Bean
    CommandLineRunner runner() {
        return args -> {
            System.out.println("CommandLineRunner running in the UnsplashApplication class...");
        };
    }
}
3
  • 6
    I believe the @PostConstruct method is part of the bean initialization. I've seen the ApplicationContext failing to load because of unsatisfied dependency due to failing @PostConstruct method.
    – egelev
    Commented Oct 24, 2020 at 9:27
  • 1
    Note that both the @PostConstruct and @PreDestroy annotations are part of Java EE. Since Java EE was deprecated in Java 9, and removed in Java 11, we have to add the dependency manually ( javax.annotation-api) to use these annotations.
    – yashodha_h
    Commented Mar 4, 2023 at 10:43
  • 1
    @egelev, that's exactly correct! that's what we should avoid doing if we were to not disturb the spring bean initialization process
    – asgs
    Commented Jun 30 at 22:40
15

Use a SmartInitializingSingleton bean in spring > 4.1

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

}

As alternative a CommandLineRunner bean can be implemented or annotating a bean method with @PostConstruct.

1
  • Can I require an Autowired dependency inside that method? I'd like to set Profiles
    – LppEdd
    Commented Jan 30, 2019 at 20:33
14

Providing an example for Dave Syer answer, which worked like a charm:

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

I really like the suggestion for usage of the EventListener annotation by @cahen (https://stackoverflow.com/a/44923402/9122660) since it is very clean. Unfortunately I could not get this to work in a Spring + Kotlin setup. What does work for Kotlin is adding the class as a method parameter:

@EventListener 
fun doSomethingAfterStartup(event: ApplicationReadyEvent) {
    System.out.println("hello world, I have just started up");
}
2
  • 1
    Put it in the spring boot application class not randomly out side @SpringBootApplication class MyApplication { @EventListener(ApplicationReadyEvent::class) fun doSomethingAfterStartup() { println("hello world, I have just started up") } }
    – Ahmed na
    Commented Feb 26, 2020 at 8:53
  • you don't need to put it necessary to the @SpringBootApplication class. any configuration class will do Commented Jun 29, 2020 at 9:14
9

You have several choices:

Using CommandLineRunner or ApplicationRunner as a Bean definition:

Spring Boot executes these towards the end of the application startup process. In most circumstances, the CommandLineRunner will do the job. Following is an example of a CommandLineRunner implementation with Java 8:

@Bean
public CommandLineRunner commandLineRunner() {
   return (args) -> System.out.println("Hello World");
}

Note that the args is the String array of arguments. You can also provide an implementation of this interface and define it as a Spring Component:

@Component
public class MyCommandLineRunner implements CommandLineRunner {

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Hello World");
    }
}

You can use the ApplicationRunner if you need better argument management. ApplicationRunner takes an ApplicationArguments instance that has enhanced argument management options.

You can also order the CommandLineRunner and ApplicationRunner beans using Spring's @Order annotation:

 @Bean
 @Order(1)
 public CommandLineRunner commandLineRunner() {
    return (args) -> System.out.println("Hello World, Order 1");
 }

 @Bean
 @Order(2)
 public CommandLineRunner commandLineRunner() {
    return (args) -> System.out.println("Hello World, Order 2");
 }

Using Spring Boot's ContextRefreshedEvent:

Spring Boot publishes several events at startup. These events indicate the completion of a phase in the application startup process. You can listen to the ContextRefreshedEvent and execute custom code:

@EventListener(ContextRefreshedEvent.class)
public void execute() {
    if(alreadyDone) {
      return;
    }
    System.out.println("hello world");
} 

ContextRefreshedEvent is published several times. Thus, ensure to put a check whether the code execution is already finished.

8

Try this one and it will run your code when the application context has fully started.

 @Component
public class OnStartServer implements ApplicationListener<ContextRefreshedEvent> {

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

Spring boot provides an ApplicationRunner interface with a run() method to be invoked at application startup. However, instead of raw String arguments passed to the callback method, we have an instance of the ApplicationArguments class.

@Component
public class AppStartupRunner implements ApplicationRunner {

    @Override
    public void run(ApplicationArguments args) throws Exception {
        //some logic here
    }
}
1
4

just implement CommandLineRunner for spring boot application. You need to implement run method,

public classs SpringBootApplication implements CommandLineRunner{

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

        }
}
3

you can use @Component

@RequiredArgsConstructor
@Component
@Slf4j
public class BeerLoader implements CommandLineRunner {
    //declare 

    @Override
    public void run(String... args) throws Exception {
        //some code here 

    }
3

If you mean running peace of code once after the application started, you can use the CommandLineRunner as below:

@SpringBootApplication
public class SpringBootApplication 
  implements CommandLineRunner {

private static Logger LOG = LoggerFactory
  .getLogger(SpringBootConsoleApplication.class);

public static void main(String[] args) {
    LOG.info("STARTING THE APPLICATION");
    SpringApplication.run(SpringBootConsoleApplication.class, args);
    LOG.info("APPLICATION FINISHED");
}

@Override
public void run(String... args) {
    // enter code you want to run after app loaded here
    LOG.info("EXECUTING : command line runner");

    for (int i = 0; i < args.length; ++i) {
        LOG.info("args[{}]: {}", i, args[i]);
    }
}

}

Otherwise, you can use the DevTools dependency, which help you to run new codes without manually restarting the application.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
    </dependency>
</dependencies>

don't forget to add these codes to your pom.xml to avoid version warnings:

   <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2021.0.3</spring-cloud.version>
    </properties>

 <dependencies>
      <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-dependencies</artifactId>
        <version>${spring-cloud.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>

give it a thump up if this was helpful to you!

2

I found Andy Brown's answer useful, indicating that SmartInitializingSingleton was better for doing some non-asynchronous task that is required before a successful start.

To give a concrete example, the great book Cloud Native Spring in Action (Manning, 2022) by Thomas Vitale gives the following example on page 122 for loading test data based upon a testdata profile by listening for ApplicationReadyEvent:

@Component
@Profile("testdata")
public class BookDataLoader {
  private final BookRepository bookRepository;

  public BookDataLoader(BookRepository bookRepository) {
    this.bookRepository = bookRepository;
  }

  @EventListener(ApplicationReadyEvent.class)
  public void loadBookTestData() {
    var book1 = new Book("1234567891", "Northern Lights",
        "Lyra Silverstar", 9.90);
    var book2 = new Book("1234567892", "Polar Journey",
        "Iorek Polarson", 12.90);
    bookRepository.save(book1);
    bookRepository.save(book2);
  }
}

Taking Andy Brown's advice, the same functionality could be implemented using SmartInitializingSingleton like this:

@Component
@Profile("testdata")
public class BookDataLoader implements SmartInitializingSingleton {
  private final BookRepository bookRepository;

  public BookDataLoader(BookRepository bookRepository) {
    this.bookRepository = bookRepository;
  }

  @Override
  public void afterSingletonsInstantiated() {
    var book1 = new Book("1234567891", "Northern Lights",
        "Lyra Silverstar", 9.90);
    var book2 = new Book("1234567892", "Polar Journey",
        "Iorek Polarson", 12.90);
    bookRepository.save(book1);
    bookRepository.save(book2);
  }
}

Note that the only differences are 1) implementing SmartInitializingSingleton and 2) overriding afterSingletonsInstantiated() instead of annotating an arbitrary method with @EventListener(ApplicationReadyEvent.class).

This approach is working in my application, and the semantics of SmartInitializingSingleton do seem to be a better fit for data initialization, based upon the Spring documentation and comments in the other answers here.

0

Best way you use CommandLineRunner or ApplicationRunner The only difference between is run() method CommandLineRunner accepts array of string and ApplicationRunner accepts ApplicationArugument.

0
0

The problem with using events or asynchronous methods is that they are launched from the main thread and control is transferred to these child thread(s).

If you have a readyness probe configured on /actuator/health, then until the logic is executed in the ApplicationReadyEvent or @PostConstruct processing method, the probe will not work and the application will restart when the readiness probe attempts timeout expires.

If you have a lot of logic (for example, warming up the cache, initializing databases, synchronizing databases based on initial data, etc.), then you can use one the following two methods for example.

  1. Using a scheduler that will be launched once(this is achieved through using the fixedDelay parameter as Long.MAX_VALUE):

    @Scheduled(fixedDelay = Long.MAX_VALUE)
    public void onStartup() {
      logger.info("Your logic here");
    }
    
  2. After starting the application, receiving a bean where you run the method:

    @SpringBootApplication
    public class YourApplication {
    
     private static ConfigurableApplicationContext context;
    
     public static void main(String[] args) {
         YourApplication.context = SpringApplication.run(RwplanApplication.class, args);
    
         context.getBean(ServiceWithOnStarupMethod.class).onStartUp();
     }
    }
    

Not the answer you're looking for? Browse other questions tagged or ask your own question.