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



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

569   11  

11 ответов:

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

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

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

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

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

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

обновление

начиная с весны 4.2+ вы также можете использовать @EventListener аннотация для наблюдения за ContextRefreshedEvent (спасибо @bphilipnyc для указания этого 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 
  }
}

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

@Component
class StartupHousekeeper {

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

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

}

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

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

то, что мы сделали, было расширение 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>

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

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

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

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

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

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

инициализируйте локаль и часовой пояс по умолчанию с помощью Spring configuration

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

@Autowired
private void configureBean(MyBean: bean) {
    bean.setConfiguration(myConfiguration);
}
AppStartListener implements ApplicationListener {
    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if(event instanceof ApplicationReadyEvent){
            System.out.print("ciao");

        }
    }
}

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

@EventListener
public void onApplicationEvent(ContextClosedEvent event) {

}

Comments

    Ничего не найдено.