Есть ли какая-нибудь особенность Spring 3 для выполнения некоторых методов при первом запуске приложения? Я знаю, что могу сделать трюк, задав метод с аннотацией @Scheduled
и он выполняется сразу после запуска, но затем он будет выполняться периодически.
Выполнить метод при запуске в Spring
Ответ 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
Ответ 8
Отправлено другое решение, которое реализует WebApplicationInitializer и вызывается намного до того, как будет создан экземпляр spring bean, если у кого-то есть этот случай использования
Инициализировать стандартную локаль и часовой пояс по умолчанию с конфигурацией 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>