Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute method on startup in Spring

Tags:

java

spring

People also ask

What happens during spring boot startup?

Spring Boot automatically configures your application based on the dependencies you have added to the project by using @EnableAutoConfiguration annotation. For example, if MySQL database is on your classpath, but you have not configured any database connection, then Spring Boot auto-configures an in-memory database.

What is Init method in spring boot?

The init-method attribute specifies a method that is to be called on the bean immediately upon instantiation. Similarly, destroymethod specifies a method that is called just before a bean is removed from the container.


If by "application startup" you mean "application context startup", then yes, there are many ways to do this, the easiest (for singletons beans, anyway) being to annotate your method with @PostConstruct. Take a look at the link to see the other options, but in summary they are:

  • Methods annotated with @PostConstruct
  • afterPropertiesSet() as defined by the InitializingBean callback interface
  • A custom configured init() method

Technically, these are hooks into the bean lifecycle, rather than the context lifecycle, but in 99% of cases, the two are equivalent.

If you need to hook specifically into the context startup/shutdown, then you can implement the Lifecycle interface instead, but that's probably unnecessary.


This is easily done with an ApplicationListener. I got this to work listening to Spring's ContextRefreshedEvent:

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class StartupHousekeeper implements ApplicationListener<ContextRefreshedEvent> {

  @Override
  public void onApplicationEvent(final ContextRefreshedEvent event) {
    // do whatever you need here 
  }
}

Application listeners run synchronously in Spring. If you want to make sure you're code is executed only once, just keep some state in your component.

UPDATE

Starting with Spring 4.2+ you can also use the @EventListener annotation to observe the ContextRefreshedEvent (thanks to @bphilipnyc for pointing this out):

import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

@Component
public class StartupHousekeeper {

  @EventListener(ContextRefreshedEvent.class)
  public void contextRefreshedEvent() {
    // do whatever you need here 
  }
}

In Spring 4.2+ you can now simply do:

@Component
class StartupHousekeeper {

    @EventListener(ContextRefreshedEvent.class)
    public void contextRefreshedEvent() {
        //do whatever
    }
}

If you are using spring-boot, this is the best answer.

I feel that @PostConstruct and other various life cycle interjections are round-about ways. These can lead directly to runtime issues or cause less than obvious defects due to unexpected bean/context lifecycle events. Why not just directly invoke your bean using plain Java? You still invoke the bean the 'spring way' (eg: through the spring AoP proxy). And best of all, it's plain java, can't get any simpler than that. No need for context listeners or odd schedulers.

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext app = SpringApplication.run(DemoApplication.class, args);

        MyBean myBean = (MyBean)app.getBean("myBean");

        myBean.invokeMyEntryPoint();
    }
}

With SpringBoot, we can execute a method on startup via @EventListener annotation

@Component
public class LoadDataOnStartUp
{   
    @EventListener(ApplicationReadyEvent.class)
    public void loadData()
    {
        // do something
    }
}


For Java 1.8 users that are getting a warning when trying to reference the @PostConstruct annotation, I ended up instead piggybacking off the @Scheduled annotation which you can do if you already have an @Scheduled job with fixedRate or fixedDelay.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@EnableScheduling
@Component
public class ScheduledTasks {

private static final Logger LOGGER = LoggerFactory.getLogger(ScheduledTasks.class);

private static boolean needToRunStartupMethod = true;

    @Scheduled(fixedRate = 3600000)
    public void keepAlive() {
        //log "alive" every hour for sanity checks
        LOGGER.debug("alive");
        if (needToRunStartupMethod) {
            runOnceOnlyOnStartup();
            needToRunStartupMethod = false;
        }
    }

    public void runOnceOnlyOnStartup() {
        LOGGER.debug("running startup job");
    }

}

What we have done was extending org.springframework.web.context.ContextLoaderListener to print something when the context starts.

public class ContextLoaderListener extends org.springframework.web.context.ContextLoaderListener
{
    private static final Logger logger = LoggerFactory.getLogger( ContextLoaderListener.class );

    public ContextLoaderListener()
    {
        logger.info( "Starting application..." );
    }
}

Configure the subclass then in web.xml:

<listener>
    <listener-class>
        com.mycomp.myapp.web.context.ContextLoaderListener
    </listener-class>
</listener>