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

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

Ответ 1

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

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

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

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

Ответ 2

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

Ответ 3

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

@Component
class StartupHousekeeper {

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

Ответ 4

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

}

Ответ 5

Если вы используете spring -boot, это лучший ответ.

Я чувствую, что @PostConstruct и другие различные междометия жизненного цикла являются круглыми способами. Это может привести непосредственно к проблемам времени выполнения или вызвать менее очевидные дефекты из-за неожиданных событий bean/context жизненного цикла. Почему бы просто не просто вызвать ваш bean с помощью простой Java? Вы все еще вызываете bean способ spring (например: через прокси-сервер spring 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();
    }
}

Ответ 6

Мы сделали расширение 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>

Ответ 7

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

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

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

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

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

Ответ 9

Если вы хотите настроить bean до того, как приложение будет запущено полностью, вы можете использовать @Autowired:

@Autowired
private void configureBean(MyBean: bean) {
    bean.setConfiguration(myConfiguration);
}

Ответ 10

AppStartListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof ApplicationReadyEvent){
            System.out.print("ciao");

        }
    }
}

Ответ 11

Вы можете использовать @EventListener в своем компоненте, который будет вызываться после запуска сервера и инициализации всех bean-компонентов.

@EventListener
public void onApplicationEvent(ContextClosedEvent event) {

}

Ответ 12

Для файла StartupHousekeeper.java расположенного в пакете com.app.startup,

Сделайте это в StartupHousekeeper.java:

@Component
public class StartupHousekeeper {

  @EventListener(ContextRefreshedEvent.class)
  public void keepHouse() {
    System.out.println("This prints at startup.");
  }
}

И сделайте это в myDispatcher-servlet.java:

<?xml version="1.0" encoding="UTF-8"?>
<beans>

    <mvc:annotation-driven />
    <context:component-scan base-package="com.app.startup" />

</beans>