Выполнить метод при запуске в Spring - PullRequest
164 голосов
/ 08 марта 2010

Есть ли какая-либо особенность Spring 3 для выполнения некоторых методов при первом запуске приложения? Я знаю, что могу сделать метод установки метода с аннотацией @Scheduled, и он выполняется сразу после запуска, но затем он будет выполняться периодически.

Ответы [ 13 ]

177 голосов
/ 08 марта 2010

Если под «запуском приложения» вы имеете в виду «запуск контекста приложения», то да, есть множество способов сделать это , причем самый простой (для bean-компонентов синглтонов) в любом случае аннотировать ваш метод с помощью @PostConstruct. Взгляните на ссылку, чтобы увидеть другие варианты, но в итоге они:

  • Методы, помеченные @PostConstruct
  • afterPropertiesSet() как определено в интерфейсе обратного вызова InitializingBean
  • Настраиваемый пользователем метод init ()

Технически, это крюки в жизненном цикле bean , а не в жизненном цикле контекста, но в 99% случаев они эквивалентны.

Если вам нужно специально подключиться к контекстному запуску / выключению, тогда вы можете реализовать Lifecycle интерфейс , но это, вероятно, не нужно.

98 голосов
/ 11 июня 2013

Это легко сделать с помощью ApplicationListener. Я получил это на работу, слушая 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 
  }
}

Слушатели приложений работают синхронно в Spring. Если вы хотите убедиться, что ваш код выполняется только один раз, просто сохраните некоторое состояние в вашем компоненте.

UPDATE

Начиная с Spring 4.2+, вы также можете использовать аннотацию @EventListener для наблюдения ContextRefreshedEvent (спасибо @ bphilipnyc за указание на это):

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 
  }
}
35 голосов
/ 04 ноября 2016

Весной 4.2+ вы можете теперь просто сделать:

@Component
class StartupHousekeeper {

    @EventListener(ContextRefreshedEvent.class)
    void contextRefreshedEvent() {
        //do whatever
    }
}
10 голосов
/ 22 июля 2015

Если вы используете весеннюю загрузку, это лучший ответ.

Я чувствую, что @PostConstruct и другие различные междометия жизненного цикла - это обходные пути. Это может привести непосредственно к проблемам во время выполнения или вызвать менее очевидные дефекты из-за непредвиденных событий жизненного цикла bean / context. Почему бы просто не напрямую вызывать ваш компонент с использованием простой Java? Вы по-прежнему вызываете бин «пружинным путем» (например, через прокси AoP пружины). И что самое приятное, это просто Java, проще не бывает. Нет необходимости в прослушивателях контекста или нечетных планировщиках.

@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();
    }
}
9 голосов
/ 09 июля 2015

Для пользователей Java 1.8, которые получают предупреждение при попытке сослаться на аннотацию @PostConstruct, я в итоге вместо этого воспользовался аннотацией @Scheduled, которую вы можете сделать, если у вас уже есть задание @Scheduled с fixedRate или 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");
    }

}
7 голосов
/ 11 июня 2013

То, что мы сделали, это расширение org.springframework.web.context.ContextLoaderListener для печати чего-либо в начале контекста.

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

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

Настройте подкласс, затем в web.xml:

<listener>
    <listener-class>
        com.mycomp.myapp.web.context.ContextLoaderListener
    </listener-class>
</listener>
3 голосов
/ 11 марта 2019

С SpringBoot мы можем выполнить метод при запуске через @EventListener аннотацию

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

3 голосов
/ 05 февраля 2016

Внимание, это рекомендуется только в том случае, если ваш runOnceOnStartup метод зависит от полностью инициализированный весенний контекст. Например: вы хотите позвонить дао с демаркацией транзакции

Вы также можете использовать запланированный метод с очень высоким значением fixedDelay

@Scheduled(fixedDelay = Long.MAX_VALUE)
public void runOnceOnStartup() {
    dosomething();
}

Преимущество заключается в том, что все приложение подключено (транзакции, Dao, ...)

в Планирование запуска задач один раз с использованием пространства имен задачи Spring

1 голос
/ 03 апреля 2016
AppStartListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof ApplicationReadyEvent){
            System.out.print("ciao");

        }
    }
}
1 голос
/ 30 октября 2014

Опубликовано другое решение, которое реализует WebApplicationInitializer и вызывается задолго до того, как будет создан экземпляр любого bean-компонента, в случае, если у кого-то есть такой вариант использования

Инициализация локали и часового пояса по умолчанию с конфигурацией Spring

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...